2

I'm working on lock application , In which when user open any app . my app will trigger and if it match with my blocklist then i'm showing lock screen to user.

What I have done so far.

public static String getTopAppName(Context context) {
            ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            String strName = "";
            try {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    strName = getLollipopFGAppPackageName(context);
    
    
                } else {
                    strName = mActivityManager.getRunningTasks(1).get(0).topActivity.getClassName();
                }}
        }

private static String getLollipopFGAppPackageName(Context ctx) {

        try {
            UsageStatsManager usageStatsManager = (UsageStatsManager) ctx.getSystemService("usagestats");
            long milliSecs = 60 * 1000;
            Date date = new Date();
            List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, date.getTime() - milliSecs, date.getTime());
            if (queryUsageStats.size() > 0) {
                Log.i("LPU", "queryUsageStats size: " + queryUsageStats.size());
            }
            long recentTime = 0;
            String recentPkg = "";
            for (int i = 0; i < queryUsageStats.size(); i++) {
                UsageStats stats = queryUsageStats.get(i);

                if (i == 0 && !"org.pervacio.pvadiag".equals(stats.getPackageName())) {
                    Log.i("LPU", "PackageName: " + stats.getPackageName() + " " + stats.getLastTimeStamp());
                }
                if (stats.getLastTimeStamp() > recentTime) {
                    recentTime = stats.getLastTimeStamp();
                    recentPkg = stats.getPackageName();
                }
            }
            return recentPkg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

I'm following this SO Answer to get top running activity in device above Lollipop. I have created background service for that.

Problem I'm facing :

1. When user block any apps from my application , I'm getting package name of that app . for example (com.google.android.talk, com.google.android.apps.maps, com.android.chrome).

At the time of service running in background . I'm getting top package name com.google.android.gsf for all google apps (maps , hangout ). So it's difficult for me to identify particular app .

I think the problem is in getLollipopFGAppPackageName() but I can't figure out what.

2. As mentioned in Some SO posts that getLollipopFGAppPackageName() can only be used at debug time not for actual implementation . So if I wont use this then what might be the correct way to implement this kind of functionality (lock app) in devices above lollipop.

Any help or guidance would be great .Thanks

Community
  • 1
  • 1
Tejas Pandya
  • 3,987
  • 1
  • 26
  • 51

1 Answers1

1

I checked out your code, the array that queryUsageStats() method return is not the same order as activities stack, this first item of this list is NOT latest opened app. You have to reorder manually this list by getLastTimeUsed.

Sort by rxJava:

 List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - milliSecs, currentTime);
                rx.Observable.from(queryUsageStats)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .toSortedList((usageStats1, usageStats2) -> compareTo(usageStats2.getLastTimeUsed(), usageStats1.getLastTimeUsed()))
                        .subscribe(usageStats -> {
                            Toast.makeText(ctx, usageStats.get(0).getPackageName(), Toast.LENGTH_SHORT).show();

                        });

Normal sort:

Collections.sort(queryUsageStats, (usageStats1, usageStats2)
                        -> compareTo(usageStats2.getLastTimeUsed(), usageStats1.getLastTimeUsed()));

Toast.makeText(ctx, queryUsageStats.get(0).getPackageName(), Toast.LENGTH_SHORT).show();

And

private int compareTo(long a, long b) {
        return a == b ? 0 : (a > b ? 1 : -1);
    }


And do not forget:

// Declare USAGE_STATS permisssion in manifest

    <uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions" />

//TODO: Check if user has already enabled Device Administrator, don't start this intent.
    Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
    startActivity(intent);


FURTHER MORE: An app that can lock other apps is NOT 100% reliable, neither some app-lock with million downloads on Google Play.
Generally the target of app-lock is when you want to share your device with other users (your girlfriend, boyfriend, children...) and still keep privacy of some specific apps that you want.
But there are some cases that can break the app-lock:

  1. Uninstall the app: even your app is enabled Device Administrator by user, they can go Device Administrator, disable your app, uninstall it, or even worse reinstall app-lock, set new password for it. If you don't know how to uninstall it again, you will be f_cked :3.

  2. Turn on Ultra power saving mode or Ultra STAMINA mode (at least on Samsung and Sony devices as I know), in this mode there are only some minimum limited apps can show and run(messages, phone call...), ALL app-lock is totally useless in this case, the shared-user can easily read your privacy SMS messages.

I used to write an app-lock before and these cases broke my dream :), PLEASE mark this answer as accepted if it can resolve your problem.
I hope you can make a better lock-app feature, reliable enough and good performance. :)

Phong Nguyen
  • 6,897
  • 2
  • 26
  • 36