FLAG_ACTIVITY_CLEAR_TOP of Activity Startup Mode

Keywords: SDK Google Android

In the past, I didn't pay much attention to the start-up mode of activity. Recently, I encountered some troubles in the project. To understand the start-up mode again, besides the four commonly used start-up modes, there are some special start-up flag s, which are also very useful.

FLAG_ACTIVITY_CLEAR_TOP Google Documents:

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

For example, consider a task consisting of the activities: A, B, C, D.
If D calls startActivity() with an Intent that resolves to the
component of activity B, then C and D will be finished and B receive
the given Intent, resulting in the stack now being: A, B.

  1. Recently, a troublesome thing happened to the project. When we do Android custom lock screen, we have a function to provide a quick access for users to use our lock screen, which can quickly open the camera and take photos. When the user has finished using the lock screen, we need to re-lock our own lock screen when they press the return key.
  2. The process of implementation is as follows: every 1s with rxjava, to detect whether the package name of the application on the top of the stack is consistent with the package name of the application we started. If it is consistent, it means that the user is still in the current application, we do not need to lock the screen. When the user presses the return button, it shows that the package name on the top of the stack has changed, and we need to perform the lock screen operation. These implementation logic are all without problems.
  3. But the problem arises. When the user jumps into the camera and clicks on the album, the package name changes. Our lock screen detects that it is inconsistent with the package name of the original jump intent, so the lock screen is locked. When the user clicks on the camera again, he finds that the camera becomes an album, the lock screen is locked, and the camera can not go in. The reason for this problem is: A. The cameras and albums in the ndroid system have different package names, but they are in the same application process, so they are an application to the outside world.
  4. How to solve this problem? There are two ideas: 1. Don't click in the album for users (which is a bit inappropriate); 2. Every time you enter the camera, make sure that it is the only activity and is displayed on the top of the stack.
  5. It can be seen that scheme one is not a particularly good solution, using MediaStore.ACTION_IMAGE_CAPTURE can let users do not enter the album entrance.
  6. The second plan is to use our FLAG_ACTIVITY_CLEAR_TOP as flag to ensure that our camera is on the top of the stack, so that the album above the camera will be cleaned up.
     Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                if (Build.VERSION.SDK_INT > 17) {
                    intent.setAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
                    List<ResolveInfo> info = getContext().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
                    if (info == null || info.size() == 0) {
                        intent.setAction(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
                    }
                }

7. Attach the code to detect the top of the stack:

```
 mCheckSubscription = Observable
                .interval(1000, TimeUnit.MILLISECONDS)
                .map(new Func1<Long, Boolean>() {
                         @Override
                         public Boolean call(Long aLong) {

                             Log.v("LockScreenManager", "checking top activity: " + validPackageName);
                             if (Build.VERSION.SDK_INT >= 21) {
                                 @SuppressWarnings("WrongConstant")
                                 UsageStatsManager usm = (UsageStatsManager) BaseApplication.getDefaultApplication().getSystemService("usagestats");
                                 long time = System.currentTimeMillis();
                                 List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
                                 if (appList != null && appList.size() > 0) {
                                     SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
                                     for (UsageStats usageStats : appList) {
                                         mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
                                     }
                                     if (!mySortedMap.isEmpty()) {
                                         String foregroundPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
                                         Log.v("LockScreenManager", "last top activity: " + foregroundPackageName);
                                         if (foregroundPackageName.equals(validPackageName)) {
                                             return false;
                                         }
                                     }
                                 }
                                 return true;
                             } else {
                                 ActivityManager am = (ActivityManager) BaseApplication.getDefaultApplication().getSystemService(Context.ACTIVITY_SERVICE);
                                 List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
                                 ComponentName componentName = taskInfo.get(0).topActivity;
                                 if (componentName.getPackageName().equals(validPackageName)) {
                                     return false;
                                 }
                                 return true;
                             }
                         }
                     }
                )
                .filter(new Func1<Boolean, Boolean>() {
                    @Override
                    public Boolean call(Boolean aBoolean) {
                        return aBoolean;
                    }
                })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Boolean>() {
                    @Override
                    public void call(Boolean b) {
                        Log.v("LockScreenManager", "showLockScreen");
                        showLockScreen();
                        stopCheckTopActivity();
                    }
                });

"`

Posted by quimbley on Mon, 17 Dec 2018 12:30:03 -0800