1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bedstead.nene.activities; 18 19 import static android.Manifest.permission.REAL_GET_TASKS; 20 import static android.os.Build.VERSION_CODES.Q; 21 22 import android.app.ActivityManager; 23 import android.content.ComponentName; 24 25 import com.android.bedstead.nene.TestApis; 26 import com.android.bedstead.nene.annotations.Experimental; 27 import com.android.bedstead.nene.exceptions.AdbException; 28 import com.android.bedstead.nene.exceptions.NeneException; 29 import com.android.bedstead.nene.packages.ComponentReference; 30 import com.android.bedstead.nene.permissions.PermissionContext; 31 import com.android.bedstead.nene.utils.ShellCommand; 32 import com.android.bedstead.nene.utils.Versions; 33 34 import java.util.List; 35 36 public final class Activities { 37 38 public static final Activities sInstance = new Activities(); 39 Activities()40 private Activities() { 41 } 42 43 44 /** 45 * Wrap the given {@link NeneActivity} subclass to use Nene APIs. 46 */ wrap(Class<E> clazz, E activity)47 public <E extends NeneActivity> Activity<E> wrap(Class<E> clazz, E activity) { 48 return new Activity<>(activity, activity); 49 } 50 51 /** 52 * Wrap the given {@link android.app.Activity} to use Nene APIs. 53 */ wrap(android.app.Activity activity)54 public LocalActivity wrap(android.app.Activity activity) { 55 return new LocalActivity(activity); 56 } 57 58 /** 59 * Get the {@link ComponentReference} of the activity currently in the foreground. 60 */ 61 @Experimental foregroundActivity()62 public ComponentReference foregroundActivity() { 63 if (!Versions.meetsMinimumSdkVersionRequirement(Q)) { 64 return foregroundActivityPreQ(); 65 } 66 try (PermissionContext p = TestApis.permissions().withPermission(REAL_GET_TASKS)) { 67 ActivityManager activityManager = 68 TestApis.context().instrumentedContext().getSystemService( 69 ActivityManager.class); 70 List<ActivityManager.RunningTaskInfo> runningTasks = activityManager.getRunningTasks(1); 71 if (runningTasks.isEmpty()) { 72 return null; 73 } 74 75 return new ComponentReference(runningTasks.get(0).topActivity); 76 } 77 } 78 foregroundActivityPreQ()79 private ComponentReference foregroundActivityPreQ() { 80 try { 81 return ShellCommand.builder("dumpsys activity top") 82 .executeAndParseOutput((dumpsysOutput) -> { 83 // The final ACTIVITY is the one on top 84 String[] activitySplits = dumpsysOutput.split("ACTIVITY "); 85 String component = activitySplits[activitySplits.length - 1] 86 .split(" ", 2)[0]; 87 ComponentName componentName = ComponentName.unflattenFromString(component); 88 return new ComponentReference(componentName); 89 }); 90 } catch (AdbException | RuntimeException e) { 91 throw new NeneException("Error getting foreground activity pre Q", e); 92 } 93 } 94 95 /** 96 * Return the current state of task locking. The three possible outcomes 97 * are {@link ActivityManager#LOCK_TASK_MODE_NONE}, 98 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED} 99 * and {@link ActivityManager#LOCK_TASK_MODE_PINNED}. 100 */ 101 @Experimental getLockTaskModeState()102 public int getLockTaskModeState() { 103 ActivityManager activityManager = 104 TestApis.context().instrumentedContext().getSystemService( 105 ActivityManager.class); 106 107 return activityManager.getLockTaskModeState(); 108 } 109 } 110