Merge "AM: introduce ActivityOptions.setLockTaskMode()."

This commit is contained in:
Charles He
2017-10-13 13:38:06 +00:00
committed by Android (Google) Code Review
7 changed files with 104 additions and 42 deletions

View File

@@ -4023,6 +4023,7 @@ package android.app {
public class ActivityOptions {
method public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
method public boolean getLockTaskMode();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4035,6 +4036,7 @@ package android.app {
method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.app.ActivityOptions setLockTaskMode(boolean);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";

View File

@@ -4185,6 +4185,7 @@ package android.app {
public class ActivityOptions {
method public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
method public boolean getLockTaskMode();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4197,6 +4198,7 @@ package android.app {
method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.app.ActivityOptions setLockTaskMode(boolean);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";

View File

@@ -4043,6 +4043,7 @@ package android.app {
public class ActivityOptions {
method public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
method public boolean getLockTaskMode();
method public static android.app.ActivityOptions makeBasic();
method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -4058,6 +4059,7 @@ package android.app {
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public void setLaunchTaskId(int);
method public void setLaunchWindowingMode(int);
method public android.app.ActivityOptions setLockTaskMode(boolean);
method public void setTaskOverlay(boolean, boolean);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);

View File

@@ -23,6 +23,7 @@ import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -157,6 +158,12 @@ public class ActivityOptions {
*/
private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
/**
* Whether the activity should be launched into LockTask mode.
* @see #setLockTaskMode(boolean)
*/
private static final String KEY_LOCK_TASK_MODE = "android:activity.lockTaskMode";
/**
* The display id the activity should be launched into.
* @see #setLaunchDisplayId(int)
@@ -278,6 +285,7 @@ public class ActivityOptions {
private int mResultCode;
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
private boolean mLockTaskMode = false;
private int mLaunchDisplayId = INVALID_DISPLAY;
@WindowConfiguration.WindowingMode
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@@ -869,6 +877,7 @@ public class ActivityOptions {
mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
break;
}
mLockTaskMode = opts.getBoolean(KEY_LOCK_TASK_MODE, false);
mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
@@ -1054,6 +1063,37 @@ public class ActivityOptions {
}
}
/**
* Gets whether the activity is to be launched into LockTask mode.
* @return {@code true} if the activity is to be launched into LockTask mode.
* @see Activity#startLockTask()
* @see android.app.admin.DevicePolicyManager#setLockTaskPackages(ComponentName, String[])
*/
public boolean getLockTaskMode() {
return mLockTaskMode;
}
/**
* Sets whether the activity is to be launched into LockTask mode.
*
* Use this option to start an activity in LockTask mode. Note that only apps permitted by
* {@link android.app.admin.DevicePolicyManager} can run in LockTask mode. Therefore, if
* {@link android.app.admin.DevicePolicyManager#isLockTaskPermitted(String)} returns
* {@code false} for the package of the target activity, a {@link SecurityException} will be
* thrown during {@link Context#startActivity(Intent, Bundle)}.
*
* Defaults to {@code false} if not set.
*
* @param lockTaskMode {@code true} if the activity is to be launched into LockTask mode.
* @return {@code this} {@link ActivityOptions} instance.
* @see Activity#startLockTask()
* @see android.app.admin.DevicePolicyManager#setLockTaskPackages(ComponentName, String[])
*/
public ActivityOptions setLockTaskMode(boolean lockTaskMode) {
mLockTaskMode = lockTaskMode;
return this;
}
/**
* Gets the id of the display where activity should be launched.
* @return The id of the display where activity should be launched,
@@ -1247,6 +1287,7 @@ public class ActivityOptions {
mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
break;
}
mLockTaskMode = otherOptions.mLockTaskMode;
mAnimSpecs = otherOptions.mAnimSpecs;
mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
mSpecsFuture = otherOptions.mSpecsFuture;
@@ -1321,6 +1362,7 @@ public class ActivityOptions {
b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
break;
}
b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode);
b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);

View File

@@ -58,6 +58,10 @@ import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
@@ -282,6 +286,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
int configChangeFlags; // which config values have changed
private boolean keysPaused; // has key dispatching been paused for it?
int launchMode; // the launch mode activity attribute.
int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override
boolean visible; // does this activity's window need to be shown?
boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
// might hide this activity?
@@ -824,23 +829,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
hasBeenLaunched = false;
mStackSupervisor = supervisor;
mRotationAnimationHint = aInfo.rotationAnimation;
if (options != null) {
pendingOptions = options;
mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind();
final int rotationAnimation = pendingOptions.getRotationAnimationHint();
// Only override manifest supplied option if set.
if (rotationAnimation >= 0) {
mRotationAnimationHint = rotationAnimation;
}
PendingIntent usageReport = pendingOptions.getUsageTimeReport();
if (usageReport != null) {
appTimeTracker = new AppTimeTracker(usageReport);
}
}
// This starts out true, since the initial state of an activity is that we have everything,
// and we shouldn't never consider it lacking in state to be removed if it dies.
haveState = true;
@@ -907,6 +895,32 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0;
mRotationAnimationHint = aInfo.rotationAnimation;
lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
if (appInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
|| lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
}
if (options != null) {
pendingOptions = options;
mLaunchTaskBehind = options.getLaunchTaskBehind();
final int rotationAnimation = pendingOptions.getRotationAnimationHint();
// Only override manifest supplied option if set.
if (rotationAnimation >= 0) {
mRotationAnimationHint = rotationAnimation;
}
final PendingIntent usageReport = pendingOptions.getUsageTimeReport();
if (usageReport != null) {
appTimeTracker = new AppTimeTracker(usageReport);
}
final boolean useLockTask = pendingOptions.getLockTaskMode();
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
}
}
}
AppWindowContainerController getWindowContainerController() {

View File

@@ -1611,6 +1611,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
// Check if someone tries to launch an unwhitelisted activity into LockTask mode.
final boolean lockTaskMode = options.getLockTaskMode();
if (lockTaskMode && !mService.mLockTaskController.isPackageWhitelisted(
UserHandle.getUserId(callingUid), aInfo.packageName)) {
final String msg = "Permission Denial: starting " + intent.toString()
+ " from " + callerApp + " (pid=" + callingPid
+ ", uid=" + callingUid + ") with lockTaskMode=true";
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
return true;

View File

@@ -43,7 +43,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -165,7 +164,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
private static final String ATTR_CALLING_PACKAGE = "calling_package";
private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
private static final String ATTR_RESIZE_MODE = "resize_mode";
private static final String ATTR_PRIVILEGED = "privileged";
private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
private static final String ATTR_MIN_WIDTH = "min_width";
private static final String ATTR_MIN_HEIGHT = "min_height";
@@ -235,10 +233,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
// of the root activity.
boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
// changes on a temporary basis.
private int mLockTaskMode; // Which tasklock mode to launch this task in. One of
// ActivityManager.LOCK_TASK_LAUNCH_MODE_*
private boolean mPrivileged; // The root activity application of this task holds
// privileged permissions.
/** Can't be put in lockTask mode. */
final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
@@ -388,9 +382,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
long lastTimeMoved, boolean neverRelinquishIdentity,
TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
int resizeMode, boolean supportsPictureInPicture, boolean privileged,
boolean _realActivitySuspended, boolean userSetupComplete, int minWidth,
int minHeight) {
int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
boolean userSetupComplete, int minWidth, int minHeight) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -426,7 +419,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
mCallingPackage = callingPackage;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
mPrivileged = privileged;
mMinWidth = minWidth;
mMinHeight = minHeight;
mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
@@ -802,6 +794,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
setIntent(r.intent, r.info);
setLockTaskAuth(r);
}
/** Sets the original intent, _without_ updating the calling uid or package. */
@@ -885,14 +878,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
mResizeMode = info.resizeMode;
mSupportsPictureInPicture = info.supportsPictureInPicture();
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
mLockTaskMode = info.lockTaskLaunchMode;
if (!mPrivileged && (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
|| mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
// Non-priv apps are not allowed to use always or never, fall back to default
mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
}
setLockTaskAuth();
}
/** Sets the original minimal width and height. */
@@ -1429,8 +1414,17 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
void setLockTaskAuth() {
setLockTaskAuth(getRootActivity());
}
private void setLockTaskAuth(@Nullable ActivityRecord r) {
if (r == null) {
mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
return;
}
final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
switch (mLockTaskMode) {
switch (r.lockTaskLaunchMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
mLockTaskAuth = mService.mLockTaskController.isPackageWhitelisted(userId, pkg)
? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
@@ -1671,7 +1665,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
String.valueOf(mSupportsPictureInPicture));
out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
if (mLastNonFullscreenBounds != null) {
out.attribute(
null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
@@ -1739,7 +1732,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
String callingPackage = "";
int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
boolean supportsPictureInPicture = false;
boolean privileged = false;
Rect bounds = null;
int minWidth = INVALID_MIN_SIZE;
int minHeight = INVALID_MIN_SIZE;
@@ -1801,8 +1793,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
resizeMode = Integer.parseInt(attrValue);
} else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) {
supportsPictureInPicture = Boolean.parseBoolean(attrValue);
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.parseBoolean(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
bounds = Rect.unflattenFromString(attrValue);
} else if (ATTR_MIN_WIDTH.equals(attrName)) {
@@ -1889,8 +1879,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
callingPackage, resizeMode, supportsPictureInPicture, privileged,
realActivitySuspended, userSetupComplete, minWidth, minHeight);
callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
userSetupComplete, minWidth, minHeight);
task.updateOverrideConfiguration(bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {