What i want to do is to update local database when an application is removed or added.
But when i got PACKAGE_REMOVED,I found it's unable to get its ApplicationInfo any more. It just throws namenotfound exception.Any suggestions?thanks.
if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {
try{
final String packageName = intent.getData().getSchemeSpecificPart();
ApplicationInfo app = pm.getApplicationInfo(packageName, 0);
final String fname = app.sourceDir;
String md5 = Util.Md5(fname);
dbm.deleteApk(md5);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The package has already been removed when the Intent PACKAGE_REMOVED is broadcast. At that point it is too late. You'll need to save the information you want BEFORE that. You can do that either when the package is installed, or you could have your application run on boot and collect the ApplicationInfo for all installed packages and save that that in a database or whatever. When the user deletes a package, you'll get the PACKAGE_REMOVED broadcast and you can find the information you want in your local database.
try:
pm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
public static final int GET_UNINSTALLED_PACKAGES
Added in API level 3
Flag parameter to retrieve some information about all applications (even uninstalled ones) which have data directories. This state could have resulted if applications have been deleted with flag DONT_DELETE_DATA with a possibility of being replaced or reinstalled in future.
Note: this flag may cause less information about currently installed applications to be returned.
Related
I need to check if a clone of my app is installed on an Android device.
It is a big security concern for my ongoing project.
Update:
I've now realised that clones are not installed but are actually able to run as a seperate instance without disturbing the original one.
Example of an app cloner:
https://play.google.com/store/apps/details?id=com.lbe.parallel.intl
How am I supposed to check at runtime that the running app has only one instance?
Android utilizes unique package strings to identify applications. Your application has a unique package string associated with it just like all Android apps.
To check if an app is installed on the device, you use the Package Manager and check with this code:
public static boolean doesUserHaveFacebookAppInstalled(Context context,
String packageString){
try{
context.getPackageManager().getApplicationInfo(packageString, 0 );
return true;
} catch( PackageManager.NameNotFoundException e ){
return false;
}
}
So if you wanted to check if, for example, Facebook is installed, you would pass in their package string of com.facebook.katana. If it returns true, it is installed, if it is false, it is not installed.
In your situation, only one package is allowed on a device at a time, but the package String can be altered when creating a build. IE, your app package String could be com.myapp.somename and a debug version could be com.myapp.somename-debug. Both would be allowed to be installed as they are unique package Strings.
If you want to check what apps are installed on the device, you can use this code and it will get all installed applications that can be launched / opened:
public static List<ResolveInfo> getAllInstalledApps(Context context){
try {
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> pkgAppsList = context.getPackageManager()
.queryIntentActivities( mainIntent, 0);
for(ResolveInfo r : pkgAppsList){
if(r != null) {
//You can use this String here to identify it while looping.
String packageString = r.toString();
}
}
return pkgAppsList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Use the results of the second code snippet to identify what apps are installed and check against the package string variations for your app to determine if other ones are installed.
There is no generic solution for this problem; some dual apps hook the system API, some run the app with different userId, and some clone the apk to a single mini VM to run.
The best approach, in my opinion, is to make your app can log-in at one place only when you open the app, connect to your server and your server forces to offline the previously logged-in device.
In that case, you may need a long connection or publish-subscribe-based messaging framework in your project (e.g., MQTT)
Based on the notification title which says "you have been logged out", I want to trigger clear app data event in android. I browsed a lot. didn't get what I needed. can someone help?
The Simplest way to do this is
private void deleteAppData() {
try {
// clearing app data
String packageName = getApplicationContext().getPackageName();
Runtime runtime = Runtime.getRuntime();
runtime.exec("pm clear "+packageName);
} catch (Exception e) {
e.printStackTrace();
} }
This will clear the data and remove your app from memory. It is equivalent to clear data option under Settings --> Application Manager --> Your App --> Clear data
As an alternate I have one more option i.e. ((ActivityManager)context.getSystemService(ACTIVITY_SERVICE)) .clearApplicationUserData();
But it has a limitation that it only work API level >=19
I want to develop an application , which gives an offer like recharge .. etc ,when it is first time installed in the device. So should i do it with help of ip address
You could use Shared Preferences to store a value on the device and you can check for it for every launch, this way you will able to know if its first time installed/launched.
https://developer.android.com/guide/topics/data/data-storage.html
If you intend to be more accurate, meaning its actually a first install and not a re-install, you will need to save:
the user information to your serve
the device information of that
user
You will need to have user managements/accounts.
cheers.
public static boolean isAppInstalled(Context context, String pkgName) {
try {
context.getPackageManager().getApplicationInfo(pkgName, 0);
return true;
}
catch (PackageManager.NameNotFoundException e) {
return false;
}
}
My android application will be preinstalled. And I want to keep tracking of preinstalled apps.
For this purpose I need somehow to save a key or a flag (which means that app is preinstalled). I will add this key to each request to my back-end and will analyze it.
I have an issue with that. An issue is about update from Google Play.
The standart workflow is the following:
1) I give to a manufacturer a special version of my application, which saves a key somehow (in Shared Prefs for example).
2) Manufacturer sell device with the app (special, modified).
3) When User get it, there definetly be next version of the app (standart, without special code) in the Google Play, so user perhaps update it without any launching (the worst case).
4) I lost my tracking possibility. (new apk fully removing never launched old one which was special)
To solve it I was listening a system broadcast ON_BOOT_COMPLETE, but its not working properly on Android 3.1+.
Have you any ideas how can I do that?
Can you install an additional .apk that only has a service? Then that service can have the key, etc. and it can listen for when your app starts and send the tracking info. Then it won't matter if your app gets upgraded; the service will still be the same.
There are some ways to know if application is system application or not. Like by checking installed directory of application or check FLAG_SYSTEM for the application.
Method 1 : -
Check location of application
public static boolean applicationIsSystemApp(Context mContext, String packageName) {
try {
ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
String appLocation = applicationInfo.publicSourceDir;
// OR String appLocation = applicationInfo.sourceDir;
// Both returns the same
// if package is pre-installed then output will be /system/app/application_name.apk
// if package is installed by user then output will be /data/app/application_name.apk
// Check if package is system app
if (appLocation != null && appLocation.startsWith("/system/app/")) {
return true;
}
} catch (NameNotFoundException e) {
e.printStackTrace(); // TODO Can handle as your logic
}
return false;
}
Method 2 : -
Check FLAG_SYSTEM of application
public static boolean applicationIsSystemApp(Context mContext, String packageName) {
try {
ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
// FLAG_SYSTEM is only set to system applications,
// this will work even if application is installed in external storage
// Check if package is system app
if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
} catch (NameNotFoundException e) {
e.printStackTrace(); // TODO Can handle as your logic
}
return false;
}
And call this method as
if (applicationIsSystemApp(getApplicationContext(), "com.example.mysystemapp")) {
// Application is system app
} else {
// Application has been installed as 3rd Party app
}
There is a property sourceDir in ApplicationInfo class. You can use it to distinguish the system app version and the upgraded one.
System app will start with "/system/app" and upgraded app will start with "/data/app"
Try something like this
try {
ApplicationInfo appInfo = this.getPackageManager().getApplicationInfo("com.example.san", 0);
boolean isSystemApp = false;
if(appInfo.sourceDir.startsWith("/system/app")){ // You can use "contains" too
isSystemApp = true;
}
} catch (Exception e) {
e.printStackTrace();
}
Note: I didnt test it.. Hope it works
One proven solution is to pre-install an APK that on have the permission: RECEIVE_BOOT_COMPLETED
Then on the very first boot - you make a quick notation that you are a PREINSTALLED to whatever persistent storage you use, preferably add a token file.
You look for this token file on all your later APK versions to determine if the running copy originates from a device which had it pre-installed or not.
This solves the mayor issues:
1) Then its OK if the user updates you APK to the latest version, you can still read this token.
2) You don't have to maintain a separate APK on google play for the pre-installed community
3) You don't have to hustle with the OEM to install multiple APK when you actually only have one App.
My app uses a microphone(AudioRecord) in a background mode,How to make the listener for phone events and voice commands (like google voice). It is necessary for me to release a microphone(AudioRecord) for use.
I found a solution to phone events: http://www.botskool.com/geeks/how-listen-phone-events-android.
to use: TelephonyManager , PhoneStateListener.
But not to voice commands. Help pls.
There is no specific way you can do this (unfortunately) and it will only be the application that attempts to use the mic resource that will get an error.
What you can do is monitor what the user is doing in the background and react accordingly. Here is the code to check if Google Now has become the foreground application:
public static boolean googleNowForeground(final Context ctx) {
final ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager.getRunningTasks(1).get(0) != null) {
final PackageManager pm = ctx.getPackageManager();
try {
final PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(
activityManager.getRunningTasks(1).get(0).topActivity.getPackageName(), 0);
if (foregroundAppPackageInfo != null) {
if (foregroundAppPackageInfo.packageName.matches(Constants.GOOGLE_NOW_PACKAGE_NAME)) {
return true;
}
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
return false;
}
This is the least 'expensive' way I've found to perform such actions, but the method above is not guaranteed to be called in future OS versions, not to mention having to hard-code the package names you are concerned with....
The 'expense' of monitoring for foreground applications that you know will conflict with your application may be somewhat minimal in comparison to permanently recording audio, but you should code your implementation wisely to minimise the monitor within certain device condition parameters.
I've investigated other methods to monitor intent broadcasts that are associated with mic resources, but they've been less successful than the above.
Requesting that the user create an 'exclude list' for the conflicting applications will allow you to dynamically monitor if they become the foreground application and react accordingly.
Hope that helps....