I have to develop an app locker for Android where the user can block apps and other users can not access these apps without an access key.
I have installed an app but I don't know how to lock this app.
Please suggest me something.
This is not how stack overflow works. You can not ask a complete solution without even trying anything.
For the most basic version of your app, you need to perform three functions.
Get a list of all the installed apps on device and show them in a ListView with check box. If the user checks any app, add the app to a different list say BlockedAppsList(which will be the list of apps which user wants to block).
You can get all the apps installed using the following code:
final PackageManager pm = getPackageManager();
//get a list of installed apps.
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo packageInfo : packages) {
Log.d(TAG, "Installed package :" + packageInfo.packageName);
Log.d(TAG, "Source dir : " + packageInfo.sourceDir);
Log.d(TAG, "Launch Activity :" + pm.getLaunchIntentForPackage(packageInfo.packageName));
}
Check the which is the current opened app. You can check by using this code:
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRecentTasks(1, ActivityManager.RECENT_WITH_EXCLUDED);
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo)(i.next());
try {
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(
info.processName, PackageManager.GET_META_DATA));
Log.w("LABEL", c.toString());
} catch (Exception e) {
// Name Not FOund Exception
}
}
Now check if the current app is present in the BlockedAppsList, if it is there, you can show any screen with a block message.
good luck!
Assuming that you store the package names of locked apps in a table called:
locks
and you want to call an activity named
PasswordActivity
when ever the users launch a locked app,
you can implement a polling mechanism like below:
public class CheckAppLaunchThread extends Thread {
private Context context;
private Handler handler;
private ActivityManager actMan;
private int timer = 100;
public static final String TAG = "App Thread";
public static String lastUnlocked;
// private String lastUnlocked;
public CheckAppLaunchThread(Handler mainHandler, Context context) {
this.context = context;
this.handler = mainHandler;
actMan = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
this.setPriority(MAX_PRIORITY);
}
#Override
public void run() {
context.startService(new Intent(context, AppLockService.class));
Looper.prepare();
String prevTasks;
String recentTasks = "";
prevTasks = recentTasks;
Log.d("Thread", "Inside Thread");
while (true) {
try {
String topPackageName = "";
if(Build.VERSION.SDK_INT >= 21) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService("usagestats");
long time = System.currentTimeMillis();
// We get usage stats for the last 10 seconds
List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*5, time);
if(stats != null) {
SortedMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
}
if(mySortedMap != null && !mySortedMap.isEmpty()) {
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
}
else {
topPackageName = actMan.getRunningAppProcesses().get(0).processName;
}
recentTasks = topPackageName;
Thread.sleep(timer);
if (recentTasks.length()==0 || recentTasks.equals(
prevTasks)) {
} else {
if (isAppLocked(recentTasks)) {
Log.d(TAG, "Locked " + recentTasks);
handler.post(new RequestPassword(context, recentTasks));
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
prevTasks = recentTasks;
}
}
class ToastRunnable implements Runnable {
String message;
public ToastRunnable(String text) {
message = text;
}
#Override
public void run() {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
class RequestPassword implements Runnable {
private Context mContext;
private String pkgName;
public RequestPassword(Context mContext, String pkgName) {
this.mContext = mContext;
this.pkgName = pkgName;
}
#Override
public void run() {
Intent passwordAct = new Intent(context, PasswordActivity.class);
passwordAct.putExtra("PACKAGE_NAME", pkgName);
passwordAct.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP);
this.mContext.startActivity(passwordAct);
}
}
private boolean isAppLocked(String packageName) {
if (packageName.equals(PasswordActivity.lastUnlocked)) {
return false;
}
PasswordActivity.lastUnlocked = null;
DatabaseHelper dbHelper = new DatabaseHelper(context);
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM locks WHERE package_name=\'"
+ packageName + "\'", null);
boolean isLocked = false;
if (cursor.moveToNext()) {
isLocked = true;
}
cursor.close();
db.close();
dbHelper.close();
return isLocked;
}
}
Now you must call the above code from your service like this:
#Override
public void onCreate() {
handler = new Handler(getMainLooper());
context = getApplicationContext();
launchChecker = new CheckAppLaunchThread(handler, context);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
while (true) {
if (!launchChecker.isAlive())
launchChecker.start();
return START_STICKY;
}
}
Warning: Since Oreo, google has restricted background services and you must figure out a way to always keep your service alive. (that is not the scope of this question) for a clue on this, consider scheduling a JobService and a broadcast receiver that would reschedule your service when ever the android kills it.
Related
I use following code to get current foreground apps package name in my app. I have one user running android 5, where this always returns null (I have other users running android 5 confirming, that my code is working!). The user installs my app, gives permissions (I checked them, my app has the permissions to use USAGE_STATS_SERVICE and then I call getCurrentForegroundPackage and it returns null. App is running a minute or so before... It's working on many other devices... Where could be the problem? Any ideas?
Code - getting foreground apps package
public static String getCurrentForegroundPackage(Context context)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
String foregroundPackage = getCurrentForegroundPackage(context, Constants.CHECK_INTERVAL_SECOND);
if (foregroundPackage == null)
foregroundPackage = getCurrentForegroundPackage(context, Constants.CHECK_INTERVAL_MINUTE);
if (foregroundPackage == null)
foregroundPackage = getCurrentForegroundPackage(context, Constants.CHECK_INTERVAL_HOUR);
return foregroundPackage;
}
else
{
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
return componentInfo.getPackageName();
}
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static String getCurrentForegroundPackage(Context context, long interval)
{
long to = System.currentTimeMillis();
long from = to - interval;
UsageStatsManager manager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
UsageEvents usageEvents = manager.queryEvents(from, to);
return getForeGroundPackage(usageEvents);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static String getForeGroundPackage(UsageEvents usageEvents)
{
String packageName = null;
long highestMoveToForegroundTimeStamp = 0;
while (usageEvents.hasNextEvent())
{
UsageEvents.Event event = new UsageEvents.Event();
usageEvents.getNextEvent(event);
if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND)
{
long timeStamp = event.getTimeStamp();
if (timeStamp > highestMoveToForegroundTimeStamp)
{
packageName = event.getPackageName();
highestMoveToForegroundTimeStamp = timeStamp;
}
}
}
return packageName;
}
Code - checking if my app has permissions
#TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean hasUsageAccess()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
try
{
PackageManager packageManager = MainApp.get().getPackageManager();
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(MainApp.get().getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) MainApp.get().getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
return mode == AppOpsManager.MODE_ALLOWED;
}
catch (Exception e)
{
L.e(PermissionUtil.class, e);
}
return false;
}
return true;
}
I have a big problem that i couldn't find solution. Need your help.
When i try to send just one message in activity using service , it works.
But when i try to send 2 message following another( that means one after other ) , sends the message twice with the same publishTopic2 and pushMsg2.
Code is :
PushService.actionPush(getApplicationContext(),publishTopic1,pushMsg1);
PushService.actionPush(getApplicationContext(),publishTopic2,pushMsg2);
1- is this from the wrong usage of syncronized keyword ?
2- is it possibe to send two msg after another without
public class PushService
extends Service
{
// this is the log tag
public static final String TAG = "DemoPushService";
public static String IncomingText = "";
private static String PushMesaj = "";
// the IP address, where your MQTT broker is running.
private static final String MQTT_HOST = "";
// the port at which the broker is running.
private static int MQTT_BROKER_PORT_NUM = 1883;
// Let's not use the MQTT persistence.
private static MqttClientPersistence MQTT_PERSISTENCE = null;
// We don't need to remember any state between the connections, so we use a
// clean start.
private static boolean MQTT_CLEAN_START = true;
// Let's set the internal keep alive for MQTT to 15 mins. I haven't tested
// this value much. It could probably be increased.
private static short MQTT_KEEP_ALIVE = 60 * 15;
// Set quality of services to 0 (at most once delivery), since we don't want
// push notifications
// arrive more than once. However, this means that some messages might get
// lost (delivery is not guaranteed)
// private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ;
private static int MQTT_QUALITY_OF_SERVICE = 2;
// The broker should not retain any messages.
// private static boolean MQTT_RETAINED_PUBLISH = false;
// MQTT client ID, which is given the broker. In this example, I also use
// this for the topic header.
// You can use this to run push notifications for multiple apps with one
// MQTT broker.
public static String MQTT_CLIENT_ID = "begining";
public static String SUBSCRIBE_TOPIC = "begining";
private static String PUBLISH_TOPIC = "begining";
// These are the actions for the service (name are descriptive enough)
private static final String ACTION_START = MQTT_CLIENT_ID + ".START";
private static final String ACTION_STOP = MQTT_CLIENT_ID + ".STOP";
private static final String ACTION_SUBSCRIBE = MQTT_CLIENT_ID
+ ".SUBSCRIBE";
private static final String ACTION_PUBLISH = MQTT_CLIENT_ID + ".PUBLISH";
private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID
+ ".KEEP_ALIVE";
private static final String ACTION_PUSHMESSAGE = MQTT_CLIENT_ID
+ ".PUSH_MESSAGE";
private static final String ACTION_PUSHMESSAGE2 = MQTT_CLIENT_ID
+ ".PUSH_MESSAGE";
private static final String ACTION_RECONNECT = MQTT_CLIENT_ID
+ ".RECONNECT";
// Connection log for the push service. Good for debugging.
private ConnectionLog mLog;
// Connectivity manager to determining, when the phone loses connection
private ConnectivityManager mConnMan;
// Notification manager to displaying arrived push notifications
private NotificationManager mNotifMan;
// Whether or not the service has been started.
private boolean mStarted;
// This the application level keep-alive interval, that is used by the
// AlarmManager
// to keep the connection active, even when the device goes to sleep.
private static final long KEEP_ALIVE_INTERVAL = 1000 * 60 * 28;
// Retry intervals, when the connection is lost.
private static final long INITIAL_RETRY_INTERVAL = 1000 * 10;
private static final long MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30;
// Preferences instance
private SharedPreferences mPrefs;
// We store in the preferences, whether or not the service has been started
public static final String PREF_STARTED = "isStarted";
// We also store the deviceID (target)
public static final String PREF_DEVICE_ID = "deviceID";
// We store the last retry interval
public static final String PREF_RETRY = "retryInterval";
// Notification title
public static String NOTIF_TITLE = "Hey !!!";
// Notification id
private static final int NOTIF_CONNECTED = 0;
// This is the instance of an MQTT connection.
private MQTTConnection mConnection;
private long mStartTime;
private static clsUser yourInfo;
public static clsOnlineUsers onlineUsers;
private static clsUser myInfo;
// Static method to start the service
public static void actionStart(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_START);
ctx.startService(i);
}
public static void actionSubscribe(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_SUBSCRIBE);
ctx.startService(i);
}
public static void actionPublish(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_PUBLISH);
ctx.startService(i);
}
// Static method to stop the service
public static void actionStop(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_STOP);
ctx.startService(i);
}
// Static method to send a keep alive message
public static void actionPing(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_KEEPALIVE);
ctx.startService(i);
}
public static void actionPush(Context ctx, String publishTopic,
String pushMsg)
{
PUBLISH_TOPIC = publishTopic;
PushMesaj = pushMsg;
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_PUSHMESSAGE);
ctx.startService(i);
}
#Override
public void onCreate()
{
super.onCreate();
log("Creating service");
mStartTime = System.currentTimeMillis();
try {
mLog = new ConnectionLog();
Log.i(TAG, "Opened log at " + mLog.getPath());
} catch (IOException e) {
Log.e(TAG, "Failed to open log", e);
}
// Get instances of preferences, connectivity manager and notification
// manager
mPrefs = getSharedPreferences(TAG, MODE_PRIVATE);
mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
mNotifMan = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mPrefs.edit().putLong(PREF_RETRY, INITIAL_RETRY_INTERVAL).commit();
mPrefs.edit().putBoolean(PREF_STARTED, false).commit();
/*
* If our process was reaped by the system for any reason we need to
* restore our state with merely a call to onCreate. We record the last
* "started" value and restore it here if necessary.
*/
handleCrashedService();
}
// This method does any necessary clean-up need in case the server has been
// destroyed by the system
// and then restarted
private void handleCrashedService()
{
if (wasStarted() == true) {
log("Handling crashed service...");
// stop the keep alives
// stopKeepAlives();
// Do a clean start
start();
}
}
#Override
public void onDestroy()
{
log("Service destroyed (started=" + mStarted + ")");
// Stop the services, if it has been started
if (mStarted == true) {
stop();
}
try {
if (mLog != null)
mLog.close();
} catch (IOException e) {
}
}
#Override
public synchronized void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
log("Service started with intent=" + intent);
if (intent == null) {
start();
return;
}
// Do an appropriate action based on the intent.
if (intent.getAction().equals(ACTION_STOP) == true) {
stop();
stopSelf();
} else if (intent.getAction().equals(ACTION_START) == true) {
start();
} else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) {
keepAlive();
} else if (intent.getAction().equals(ACTION_PUBLISH) == true) {
publish();
} else if (intent.getAction().equals(ACTION_SUBSCRIBE) == true) {
subscribe();
} else if (intent.getAction().equals(ACTION_PUSHMESSAGE) == true) {
sendMessage();
} else if (intent.getAction().equals(ACTION_RECONNECT) == true) {
if (isNetworkAvailable()) {
reconnectIfNecessary();
}
}
}
private void subscribe()
{
// TODO Auto-generated method stub
try {
mConnection.subscribeToTopic(SUBSCRIBE_TOPIC);
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void publish()
{
try {
// Send a keep alive, if there is a connection.
if (mStarted == true && mConnection != null) {
mConnection.sendPushMessage(1);
}
} catch (MqttException e) {
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"), e);
mConnection.disconnect();
mConnection = null;
cancelReconnect();
}
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
// log helper function
private void log(String message)
{
log(message, null);
}
private void log(String message, Throwable e)
{
if (e != null) {
Log.e(TAG, message, e);
} else {
Log.i(TAG, message);
}
if (mLog != null) {
try {
mLog.println(message);
} catch (IOException ex) {
}
}
}
// Reads whether or not the service has been started from the preferences
private boolean wasStarted()
{
return mPrefs.getBoolean(PREF_STARTED, false);
}
// Sets whether or not the services has been started in the preferences.
private void setStarted(boolean started)
{
mPrefs.edit().putBoolean(PREF_STARTED, started).commit();
mStarted = started;
}
private synchronized void start()
{
log("Starting service...");
// Do nothing, if the service is already running.
if (mStarted == true) {
Log.w(TAG, "Attempt to start connection that is already active");
return;
}
// Establish an MQTT connection
connect();
// Register a connectivity listener
registerReceiver(mConnectivityChanged, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
}
private synchronized void stop()
{
// Do nothing, if the service is not running.
if (mStarted == false) {
Log.w(TAG, "Attempt to stop connection not active.");
return;
}
// Save stopped state in the preferences
setStarted(false);
// Remove the connectivity receiver
unregisterReceiver(mConnectivityChanged);
// Any existing reconnect timers should be removed, since we explicitly
// stopping the service.
cancelReconnect();
// Destroy the MQTT connection if there is one
if (mConnection != null) {
mConnection.disconnect();
mConnection = null;
}
}
private clsUser setUserInfo(String deviceId)
{
clsUser u = new clsUser();
dbUser du = new dbUser(getApplicationContext(), dbUser.DATABASE_NAME,
null, dbUser.DATABASE_VERSION);
Cursor c1 = du.Getby(null, null, null, null, null, null, null, null,
null, deviceId, null, null, null);
u = du.setProperties(c1);
c1.close();
du.close();
return u;
}
//
private synchronized void connect()
{
log("Connecting...");
// Create a new connection only if the device id is not NULL
if (MQTT_CLIENT_ID == null) {
log("Device ID not found.");
} else {
try {
MQTT_CLIENT_ID = Config.id(getApplication());
myInfo = setUserInfo(MQTT_CLIENT_ID);
mConnection = new MQTTConnection(MQTT_HOST, "user/"
+ MQTT_CLIENT_ID + "/#");
} catch (MqttException e) {
// Schedule a reconnect, if we failed to connect
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"));
if (!isNetworkAvailable()) {
scheduleReconnect(mStartTime);
}
}
setStarted(true);
}
}
private synchronized void keepAlive()
{
try {
// Send a keep alive, if there is a connection.
if (mStarted == true && mConnection != null) {
mConnection.sendKeepAlive();
}
} catch (MqttException e) {
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"), e);
mConnection.disconnect();
mConnection = null;
cancelReconnect();
}
}
private void sendMessage()
{
try {
// Send a keep alive, if there is a connection.
if (mStarted == true && mConnection != null) {
mConnection.sendPushMessage(); // this does the job
}
} catch (MqttException e) {
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"), e);
mConnection.disconnect();
mConnection = null;
cancelReconnect();
}
}
// Schedule application level keep-alives using the AlarmManager
private void startKeepAlives()
{
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + KEEP_ALIVE_INTERVAL,
KEEP_ALIVE_INTERVAL, pi);
}
// Remove all scheduled keep alives
private void stopKeepAlives()
{
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.cancel(pi);
}
// We schedule a reconnect based on the starttime of the service
public void scheduleReconnect(long startTime)
{
// the last keep-alive interval
long interval = mPrefs.getLong(PREF_RETRY, INITIAL_RETRY_INTERVAL);
// Calculate the elapsed time since the start
long now = System.currentTimeMillis();
long elapsed = now - startTime;
log(String.valueOf(elapsed));
// Set an appropriate interval based on the elapsed time since start
if (elapsed < interval) {
interval = Math.min(interval * 4, MAXIMUM_RETRY_INTERVAL);
} else {
interval = INITIAL_RETRY_INTERVAL;
}
log("Rescheduling connection in " + interval + "ms.");
// Save the new internval
mPrefs.edit().putLong(PREF_RETRY, interval).commit();
// Schedule a reconnect using the alarm manager.
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_RECONNECT);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.set(AlarmManager.RTC_WAKEUP, now + interval, pi);
}
// Remove the scheduled reconnect
public void cancelReconnect()
{
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_RECONNECT);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.cancel(pi);
}
private synchronized void reconnectIfNecessary()
{
if (mStarted == true && mConnection == null) {
log("Reconnecting...");
connect();
}
}
private class MQTTConnection
implements MqttCallback
{
MqttClient mqttClient = null;
MqttConnectOptions conOpt;
String myDeviceId;
// Creates a new connection given the broker address and initial topic
public MQTTConnection(String brokerHostName, String initTopic)
throws MqttException
{
// Create connection spec
}
private void publish(String topicName, int qos, String payload,
boolean retained) throws MqttException
{
}
/*
* Sends a message to the message broker, requesting that it be
* published to the specified topic.
*/
private void publishToTopic(String topicName, String message)
throws MqttException
{
if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
// quick sanity check - don't try and publish if we don't have
// a connection
log("No connection to public to");
} else {
publish(topicName, MQTT_QUALITY_OF_SERVICE, message, false);
}
}
/*
* Send a request to the message broker to be sent messages published
* with the specified topic name. Wildcards are allowed.
*/
private void subscribeToTopic(String topicName1) throws MqttException
{
if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
// quick sanity check - don't try and subscribe if we don't have
// a connection
log("Subscribtion failed : Connection error" + "No connection");
} else {
mqttClient.subscribe(topicName1, 0);
Log.v(TAG, "Subscribe To : " + topicName1);
}
}
public void sendPushMessage(int sira) throws MqttException
{
publishToTopic(PUBLISH_TOPIC, PushMesaj);
}
}
}
When you call actionPush(), it does the following:
PUBLISH_TOPIC = publishTopic;
PushMesaj = pushMsg;
which saves the arguments in private static variables and then calls startService. If you do this twice, you will overwrite the private static variables with the second set of arguments.
You need to understand that the call to startService() is not synchronous. It doesn't start the service immediately and call onStart() before the method returns. The service will get started and the call to onStart() will occur sometime later (timing isn't under your control here).
You want to put these parameters in the Intent that you use to start the service, and retrieve the arguments from the Intent in onStart(). You can't reliably use static variables to do this.
EDIT: ADD CODE DETAILS
Change actionPush() to this:
static final String EXTRA_TOPIC = "EXTRA_TOPIC";
static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";
public static void actionPush(Context ctx, String publishTopic,
String pushMsg)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_PUSHMESSAGE);
i.putExtra(EXTRA_TOPIC, publishTopic);
i.putExtra(EXTRA_MESSAGE, pushMsg);
ctx.startService(i);
}
and in onStart() you can get the arguments out of the Intent like this:
String topic = intent.getStringExtra(EXTRA_TOPIC);
String message = intent.getStringExtra(EXTRA_MESSAGE);
I'm not going to rewrite the entire program for you. You'll have to figure out now what to do with the arguments. Maybe you can now store them in private static variables, but I don't know enough about your program to be able to say if that will work. A better solution would be to pass the arguments through the various methods that you've defined until they get down to the methods where they are used.
My application has a database where queued items will be stored if it doesn't notice any connectivity to Wifi or mobile network, like 3G og 4G. My problem is:
I have a BroadcastReciever which is registrered this way:
#Override
public void onResume() {
super.onResume();
if(networkMonitor == null)
networkMonitor = new CaseQueueReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkMonitor, filter);
}
My BroadcastReciever is starting a Service to pick out items from this database and send them over either a webservice or mail. My BrodcastReciever is like this:
public class CaseQueueReceiver extends BroadcastReceiver {
boolean available;
QueueDB queueDB;
int count;
public CaseQueueReceiver() {
queueDB = new QueueDB(ContextHelper.context());
count = queueDB.countUnsentCases();
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
String typeName = info.getTypeName();
String subtypeName = info.getSubtypeName();
available = info.isAvailable();
Log.i("Network Monitor", "Network Type: " + typeName + ", subtype: " + subtypeName + ", available: " + available);
if (available && count > 0) {
Intent service = new Intent(context, SendQueuedCasesService.class);
context.startService(service);
}
}
}
}
As you can see if the internet connection is available and the database contains something, I will start a service to send these items in the database.
My Service looks like this:
public class SendQueuedCasesService extends Service {
boolean available;
DatabaseHandler db;
QueueDB queueDB;
HashMap<String, String> queueHashMap;
CreateTransaction transaction;
String pcn, file;
int sent;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
db = new DatabaseHandler(ContextHelper.context());
queueDB = new QueueDB(ContextHelper.context());
queueHashMap = new HashMap<String, String>();
transaction = new CreateTransaction(ContextHelper.context());
queueDB = new QueueDB(this);
int count = queueDB.countUnsentCases();
Log.w("Unsent cases count: ", Integer.toString(count));
if (count > 0) {
queueHashMap = queueDB.getUnsetCases();
Iterator<Entry<String, String>> it = queueHashMap.entrySet().iterator();
while(it.hasNext()) {
Map.Entry pairs = it.next();
pcn = pairs.getKey().toString();
Log.w("PCN in Queued Cases: ", pcn);
file = pairs.getKey().toString();
Log.w("Nist File Path: ", file);
try
{
sent = transaction.createTransaction(pcn, file);
if(sent == -2)
{
queueDB.deleteUnSentCase(pcn);
db.updateDB(pcn, "");
}
else
break;
} catch(MailException e) {
Log.e("MailException: ", e.getMessage());
}
}
Intent i = new Intent(this, WorkflowChooser.getCurrentWorkflow());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
}
}
My problem is that when I start the application this will block the UI for a while and then show the UI. A other problems is that this service isn't triggered if I turn off and the on the WiFi again. Why is this happening?
My problem is that when I start the application this will block the UI for a while and then show the UI.
Service runs in UI thread. That's the problem.
You can try to use IntentService. It will handle all the threading for you automatically.
You should create an AsyncTask or a new thread which handles the Service.
This question already has answers here:
Get active Application name in Android
(3 answers)
Closed 6 months ago.
Please suggest me how can I get current open application name, even if there is home screen on device then I will find "Home screen is open".
Use an AccessibilityService
You can detect the currently active window by using an AccessibilityService.
In the onAccessibilityEvent callback, check for the TYPE_WINDOW_STATE_CHANGED event type to determine when the current window changes.
Check if the window is an activity by calling PackageManager.getActivityInfo().
I tested and working in Android 2.2 (API 8) through Android 7.1 (API 25).
public class MyAccessibilityService extends AccessibilityService {
#Override
protected void onServiceConnected() {
super.onServiceConnected();
//Configure these here for compatibility with API 13 and below.
AccessibilityServiceInfo config = new AccessibilityServiceInfo();
config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
if (Build.VERSION.SDK_INT >= 16)
//Just in case this helps
config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
setServiceInfo(config);
}
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
Log.d("ABC-",accessibilityEvent.getPackageName()+" -- "+accessibilityEvent.getClassName());
if (accessibilityEvent.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (accessibilityEvent.getPackageName() != null && accessibilityEvent.getClassName() != null) {
ComponentName componentName = new ComponentName(
accessibilityEvent.getPackageName().toString(),
accessibilityEvent.getClassName().toString()
);
ActivityInfo activityInfo = tryGetActivity(componentName);
boolean isActivity = activityInfo != null;
if (isActivity)
Log.i("CurrentActivity", componentName.flattenToShortString());
}
}
}
private ActivityInfo tryGetActivity(ComponentName componentName) {
try {
return getPackageManager().getActivityInfo(componentName, 0);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
#Override
public void onInterrupt() {
}
}
You can also list running tasks with the code below:
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(ACTIVITY_SERVICE);
List li = am.getRunningTasks(100);
Iterator i = li.iterator();
PackageManager pm = getApplicationContext().getPackageManager();
while (i.hasNext()) {
try {
ActivityManager.RunningTaskInfo info = (ActivityManager.RunningTaskInfo)(i.next());
String ac = info.baseActivity.getPackageName();
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(
ac, PackageManager.GET_META_DATA));
Log.v("asd", c.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
For me the above example did not work. So i ended up using this:
ActivityManager am = (ActivityManager) this
.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RecentTaskInfo> l = am.getRecentTasks(1,
ActivityManager.RECENT_WITH_EXCLUDED);
Iterator<ActivityManager.RecentTaskInfo> i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
try {
Intent intent = i.next().baseIntent;
List<ResolveInfo> list = pm.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(
list.get(0).activityInfo.packageName,
PackageManager.GET_META_DATA));
Toast.makeText(this, "Application name: " + c.toString(),
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(this,
"Application name not found: " + e.toString(),
Toast.LENGTH_LONG).show();
}
}
With this you can get the current application name
Resources appR = getApplicationContext().getResources();
CharSequence txt = appR.getText(appR.getIdentifier("app_name","string", getApplicationContext().getPackageName()));
System.out.println(txt+" APp Name");
Simply using this code
getActivity().getApplicationInfo().packageName
It gives you application info, and then call the package name.
for some specific requirement
I am required to change Android Default Home application
with my customized Home application ( a setting inside my app that will toggle default home = my application or previous home)
I don't want the user to travel android settings that are very complicated.
Can any one help me out like where it registers launcher.apk for default
home application or how to change that
The only thing I could find was that old question: How to change default Android's Desktop application?
but no answers at all.
I have seen HomeSwitcher in the Market that do the trick, but no answer for the developer that might certainly be busy.
EDIT
I found this on the web http://www.mail-archive.com/android-developers#googlegroups.com/msg74167.html
But I got the same issue:
this is my code:
private void makePreferred() {
PackageManager pm = getPackageManager();
IntentFilter f = new IntentFilter("android.intent.action.MAIN");
f.addCategory("android.intent.category.HOME");
f.addCategory("android.intent.category.DEFAULT");
ComponentName cn = new ComponentName("com.example.android.home", "com.example.android.home.Home");
pm.addPreferredActivity(f, IntentFilter.MATCH_CATEGORY_EMPTY, null, cn);
I have the android.permission.SET_PREFERRED_APPLICATIONS set in the
manifest. After executing the code above, the logs claim things have
been added like expected (same logs as when I tick off "Make default"
from IntentResolver's list). However, when I proceed by clicking home,
the list still shows up and the logs say:
INFO/PackageManager(52): Result set changed, dropping preferred
activity for Intent { act=android.intent.action.MAIN cat=
[android.intent.category.HOME] flg=0x10200000 } type null
So it seems the resolver deletes the default entry. Am I doing
something wrong, or is this a security measure? What are the ideas
behind this?
I did an extensive research on that and starting from 2.2 there is no way to do that. The only way is using some hacking that toddler lock app does but this app put samsung phones recently in the infinite loop, so it is a risky approach.
if you look at the froyo source code here of packagemanager class, you will see this small condition in the addPreferredActivity method:
if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring addPreferredActivity() from uid"
+ Binder.getCallingUid());
return;
}
HomeSwitcher does not work properly on 2.2 since it uses this very method and developer made a comment on app page "Froyo(2.2) is not supported
due to the API change"
"Result set changed" means that the set of packages matching that intent has changed from the set you specified when you created the default - - so the default is no longer valid. Your list of components (which you are currently setting to null) needs to contain all homescreen apps present on device, not just yours.
Here's example code that I have tested (using adb shell am start http://www.google.co.uk/ ) and used to set the default browser. XXX represents a customer name that I had to black out.
Note that in order to call addPreferredActivity you must have compiled against a minimum-sdk version of 8 (2.2) and you must have specified the SET_PREFERRED_APPLICATIONS permission. That permission is protection level 2, so you need to be signed with the same certificate as PackageManager.
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.VIEW");
filter.addCategory("android.intent.category.DEFAULT");
filter.addDataScheme("http");
Context context = getApplicationContext();
ComponentName component = new ComponentName("com.opera.mini.XXX", "com.opera.mini.XXX.CustomerBrowser");
ComponentName[] components = new ComponentName[] {new ComponentName("com.android.browser", "com.android.browser.BrowserActivity"),
component};
pm.addPreferredActivity(filter, IntentFilter.MATCH_CATEGORY_SCHEME, components, component);
ETA - if you marked this response down, could you let me know why. The code I posted above is tested and working...
startActivity(new Intent(Settings.ACTION_HOME_SETTINGS));
This code works on my ICS device: I use a service that is sensible to some call, one of them is called SET_PREFERRED_LAUNCHER, the put in a bundle your new default Launcher package (PREFERRED_PACKAGE_KEY) and it's activity (PREFERRED_ACTIVITY_KEY)
Method installPackageMethod = null;
Method deletePackageMethod = null;
Method setPreferredActivityMethod = null;
Method replacePreferredActivityMethod = null;
Object pm = null;
#Override
public void onCreate() {
super.onCreate();
if (pm == null)
pm = getPackageManager();
try {
if (setPreferredActivityMethod == null)
setPreferredActivityMethod = pm.getClass().getMethod(
"addPreferredActivity", IntentFilter.class, int.class,
ComponentName[].class, ComponentName.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private final class ServiceHandler extends Handler {
private Context context;
public ServiceHandler(Looper looper, Context ctx) {
super(looper);
context = ctx;
}
#Override
public void handleMessage(Message msg) {
Intent intent = (Intent) msg.getData().getParcelable(
UPDATER_SERVICE_ACTION);
int request = intent.getIntExtra(
REQUEST_KEY,
REQUEST_UNKNOWN);
Bundle bundle = intent.getExtras();
switch (request) {
case INSTALL_APPLICATION: {
if (bundle != null) {
String appPath = bundle
.getString(APP_PATH_KEY);
if (appPath != null) {
LogUtil.e(TAG, "try to install " + appPath);
try {
am.installPackage(appPath);
} catch (Exception e) {
e.printStackTrace();
}
LogUtil.e(TAG, "install of " + appPath + " done");
}
}
break;
}
case UNISTALL_PACKAGE: {
if (bundle != null) {
String packagename = bundle
.getString(PACKAGE_NAME_KEY);
if (packagename != null) {
LogUtil.e(TAG, "unistall " + packagename);
try {
deletePackageMethod
.invoke(pm, packagename, null, 0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
break;
}
case SET_PREFERRED_LAUNCHER: {
if (bundle != null) {
String package_name = bundle
.getString(PREFERRED_PACKAGE_KEY);
if (package_name == null) {
LogUtil.e(TAG,
"WARNING: setDefaultActivity cannot continue, package is NULL");
return;
}
String activity_name = bundle
.getString(PREFERRED_ACTIVITY_KEY);
if (activity_name == null) {
LogUtil.e(TAG,
"WARNING: setDefaultActivity cannot continue, activity is NULL");
return;
}
LogUtil.e(TAG, "setDefaultActivity activity="
+ activity_name + " package=" + package_name);
IntentFilter filter = new IntentFilter(
"android.intent.action.MAIN");
filter.addCategory("android.intent.category.HOME");
filter.addCategory("android.intent.category.DEFAULT");
ComponentName[] components = new ComponentName[] {
new ComponentName("com.android.launcher",
"com.android.launcher2.Launcher"),
new ComponentName(package_name, activity_name) };
ComponentName activity = new ComponentName(package_name,
activity_name);
try {
setPreferredActivityMethod.invoke(pm, filter,
IntentFilter.MATCH_CATEGORY_EMPTY, components,
activity);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
Remember to add in your manifest file this permission:
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"/>
Usage:
public void setPreferredLauncher(String activity_name,String package_name)
{
Intent intent = new Intent(UPDATER_SERVICE_ACTION);
intent.putExtra(REQUEST_KEY, SET_PREFERRED_LAUNCHER);
intent.putExtra(PREFERRED_ACTIVITY_KEY, activity_name);
intent.putExtra(PREFERRED_PACKAGE_KEY, package_name);
context.startService(intent);
}
where:
public static final String _UPDATER_SERVICE_ACTION = "com.android.updaterservice.ACTION";
public static final String REQUEST_KEY = "com.android.updaterservice.REQUEST_KEY";
public static final String PACKAGE_NAME_KEY = "com.android.updaterservice.PACKAGE_NAME_KEY";
public static final String APP_PATH_KEY = "com.android.updaterservice.APP_PATH_KEY";
public static final String PREFERRED_ACTIVITY_KEY = "com.android.updaterservice.PREFERRED_ACTIVITY_KEY";
public static final String PREFERRED_PACKAGE_KEY = "com.android.updaterservice.PREFERRED_PACKAGE_KEY";
public static final String INSTALL_PACKAGE_RESULT = "com.android.updaterservice.INSTALL_PACKAGE_RESULT";
public static final String PACKAGE_NAME = "PACKAGE_NAME";
public static final String INSTALL_SUCCEEDED = "INSTALL_SUCCEEDED";
public static final int REQUEST_UNKNOWN = -1;
public static final int INSTALL_APPLICATION = 1;
public static final int UNISTALL_PACKAGE = 2;
public static final int SET_PREFERRED_LAUNCHER = 3;