diff options
| author | 2017-01-19 17:09:28 +0000 | |
|---|---|---|
| committer | 2017-02-13 23:22:34 +0000 | |
| commit | 3c82d3d5bfea9b6483ad0264e6956eb5a00a2a4a (patch) | |
| tree | 786fd05e66063c3a582ad2b9befbc8294f420f81 | |
| parent | f9a55d42d2e2adbf5895d04e4790debb145508ed (diff) | |
Theme work lock activity with the task primaryColor
This involves adding another system RPC, getTaskDescription(taskId)
gated on MANAGE_ACTIVITY_STACKS permission.
Bug: 31001762
Test: runtest -x frameworks/base/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
Change-Id: Ieb996f7fab5bc79737df570e35733551118118d3
6 files changed, 187 insertions, 32 deletions
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index c842f788feda..ca17e18ae2e1 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -210,6 +210,7 @@ interface IActivityManager { boolean killPids(in int[] pids, in String reason, boolean secure); List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags); ActivityManager.TaskThumbnail getTaskThumbnail(int taskId); + ActivityManager.TaskDescription getTaskDescription(int taskId); // Retrieve running application processes in the system List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses(); // Get device configuration diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java index 23eaed9007ac..32b5862e2b6b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java @@ -17,7 +17,6 @@ package com.android.systemui.keyguard; import static android.app.ActivityManager.TaskDescription; -import static android.app.ActivityManager.StackId; import android.annotation.ColorInt; import android.annotation.UserIdInt; @@ -32,13 +31,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; -import android.graphics.Rect; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.view.View; +import com.android.internal.annotations.VisibleForTesting; + /** * Bouncer between work activities and the activity used to confirm credentials before unlocking * a managed profile. @@ -51,52 +51,39 @@ public class WorkLockActivity extends Activity { private static final String TAG = "WorkLockActivity"; /** - * ID of the locked user that this activity blocks access to. + * Contains a {@link TaskDescription} for the activity being covered. */ - @UserIdInt - private int mUserId; - + static final String EXTRA_TASK_DESCRIPTION = + "com.android.systemui.keyguard.extra.TASK_DESCRIPTION"; + /** - * {@see KeyguardManager} + * Cached keyguard manager instance populated by {@link #getKeyguardManager}. + * @see KeyguardManager */ private KeyguardManager mKgm; - /** - * {@see DevicePolicyManager} - */ - private DevicePolicyManager mDpm; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId()); - mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); - mKgm = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); - - final IntentFilter lockFilter = new IntentFilter(); - lockFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED); - registerReceiverAsUser(mLockEventReceiver, UserHandle.ALL, lockFilter, - /* permission */ null, /* scheduler */ null); + registerReceiverAsUser(mLockEventReceiver, UserHandle.ALL, + new IntentFilter(Intent.ACTION_DEVICE_LOCKED_CHANGED), /* permission */ null, + /* scheduler */ null); // Once the receiver is registered, check whether anything happened between now and the time // when this activity was launched. If it did and the user is unlocked now, just quit. - if (!mKgm.isDeviceLocked(mUserId)) { + if (!getKeyguardManager().isDeviceLocked(getTargetUserId())) { finish(); return; } - // Get the organization color; this is a 24-bit integer provided by a DPC, guaranteed to - // be completely opaque. - final @ColorInt int color = mDpm.getOrganizationColorForUser(mUserId); - // Draw captions overlaid on the content view, so the whole window is one solid color. setOverlayWithDecorCaptionEnabled(true); // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with // redaction switched on. final View blankView = new View(this); - blankView.setBackgroundColor(color); + blankView.setBackgroundColor(getPrimaryColor()); setContentView(blankView); } @@ -127,26 +114,28 @@ public class WorkLockActivity extends Activity { @Override public void setTaskDescription(TaskDescription taskDescription) { - // Use the previous activity's task description. + // Leave unset so we use the previous activity's task description. } private final BroadcastReceiver mLockEventReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, mUserId); - if (userId == mUserId && !mKgm.isDeviceLocked(mUserId)) { + final int targetUserId = getTargetUserId(); + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, targetUserId); + if (userId == targetUserId && !getKeyguardManager().isDeviceLocked(targetUserId)) { finish(); } } }; private void showConfirmCredentialActivity() { - if (isFinishing() || !mKgm.isDeviceLocked(mUserId)) { + if (isFinishing() || !getKeyguardManager().isDeviceLocked(getTargetUserId())) { // Don't show the confirm credentials screen if we are already unlocked / unlocking. return; } - final Intent credential = mKgm.createConfirmDeviceCredentialIntent(null, null, mUserId); + final Intent credential = getKeyguardManager() + .createConfirmDeviceCredentialIntent(null, null, getTargetUserId()); if (credential == null) { return; } @@ -181,4 +170,32 @@ public class WorkLockActivity extends Activity { final View view = getWindow().getDecorView(); return ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.getWidth(), view.getHeight()); } + + private KeyguardManager getKeyguardManager() { + if (mKgm == null) { + mKgm = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + } + return mKgm; + } + + @VisibleForTesting + @UserIdInt + final int getTargetUserId() { + return getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId()); + } + + @VisibleForTesting + @ColorInt + final int getPrimaryColor() { + final TaskDescription taskDescription = (TaskDescription) + getIntent().getExtra(EXTRA_TASK_DESCRIPTION); + if (taskDescription != null && Color.alpha(taskDescription.getPrimaryColor()) == 255) { + return taskDescription.getPrimaryColor(); + } else { + // No task description. Use an organization color set by the policy controller. + final DevicePolicyManager devicePolicyManager = (DevicePolicyManager) + getSystemService(Context.DEVICE_POLICY_SERVICE); + return devicePolicyManager.getOrganizationColorForUser(getTargetUserId()); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java index e6483f6332ba..a49c4820aafd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java @@ -31,17 +31,21 @@ import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; public class WorkLockActivityController { private final Context mContext; + final SystemServicesProxy mSsp; public WorkLockActivityController(Context context) { mContext = context; + mSsp = SystemServicesProxy.getInstance(context); + EventBus.getDefault().register(this); - SystemServicesProxy.getInstance(context).registerTaskStackListener(mLockListener); + mSsp.registerTaskStackListener(mLockListener); } private void startWorkChallengeInTask(int taskId, int userId) { Intent intent = new Intent(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER) .setComponent(new ComponentName(mContext, WorkLockActivity.class)) .putExtra(Intent.EXTRA_USER_ID, userId) + .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, mSsp.getTaskDescription(taskId)) .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 49074a6f535d..eae1b8155486 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -868,6 +868,14 @@ public class SystemServicesProxy { return null; } + public ActivityManager.TaskDescription getTaskDescription(int taskId) { + try { + return mIam.getTaskDescription(taskId); + } catch (RemoteException e) { + return null; + } + } + /** * Returns the given icon for a user, badging if necessary. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java new file mode 100644 index 000000000000..9b868dbff714 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.keyguard; + +import static android.app.ActivityManager.TaskDescription; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.when; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import android.annotation.ColorInt; +import android.annotation.UserIdInt; +import android.app.KeyguardManager; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Looper; + +import com.android.systemui.keyguard.WorkLockActivity; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * runtest systemui -c com.android.systemui.keyguard.WorkLockActivityTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class WorkLockActivityTest { + private static final @UserIdInt int USER_ID = 270; + private static final String TASK_LABEL = "task label"; + + private @Mock DevicePolicyManager mDevicePolicyManager; + private @Mock KeyguardManager mKeyguardManager; + private @Mock Context mContext; + + private WorkLockActivity mActivity; + + private static class WorkLockActivityTestable extends WorkLockActivity { + WorkLockActivityTestable(Context baseContext) { + super(); + attachBaseContext(baseContext); + } + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mContext.getSystemService(eq(Context.DEVICE_POLICY_SERVICE))) + .thenReturn(mDevicePolicyManager); + when(mContext.getSystemService(eq(Context.KEYGUARD_SERVICE))) + .thenReturn(mKeyguardManager); + + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mActivity = new WorkLockActivityTestable(mContext); + } + + @Test + public void testBackgroundAlwaysOpaque() throws Exception { + final @ColorInt int orgColor = Color.rgb(250, 199, 67); + when(mDevicePolicyManager.getOrganizationColorForUser(eq(USER_ID))).thenReturn(orgColor); + + final @ColorInt int opaqueColor= Color.rgb(164, 198, 57); + final @ColorInt int transparentColor = Color.argb(0, 0, 0, 0); + TaskDescription opaque = new TaskDescription(null, null, opaqueColor); + TaskDescription transparent = new TaskDescription(null, null, transparentColor); + + // When a task description is provided with a suitable (opaque) primaryColor, it should be + // used as the scrim's background color. + mActivity.setIntent(new Intent() + .putExtra(Intent.EXTRA_USER_ID, USER_ID) + .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, opaque)); + assertEquals(opaqueColor, mActivity.getPrimaryColor()); + + // When a task description is provided but has no primaryColor / the primaryColor is + // transparent, the organization color should be used instead. + mActivity.setIntent(new Intent() + .putExtra(Intent.EXTRA_USER_ID, USER_ID) + .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, transparent)); + assertEquals(orgColor, mActivity.getPrimaryColor()); + + // When no task description is provided at all, it should be treated like a transparent + // description and the organization color shown instead. + mActivity.setIntent(new Intent() + .putExtra(Intent.EXTRA_USER_ID, USER_ID)); + assertEquals(orgColor, mActivity.getPrimaryColor()); + } +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 93fb9114beba..c03c562307a6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9580,6 +9580,20 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public ActivityManager.TaskDescription getTaskDescription(int id) { + synchronized (this) { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "getTaskDescription()"); + final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked( + id, !RESTORE_FROM_RECENTS, INVALID_STACK_ID); + if (tr != null) { + return tr.lastTaskDescription; + } + } + return null; + } + + @Override public int addAppTask(IBinder activityToken, Intent intent, ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException { final int callingUid = Binder.getCallingUid(); |