summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/widget/TextView.java6
-rw-r--r--core/proto/android/server/activitymanagerservice.proto7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java2
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java218
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java3
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java10
9 files changed, 197 insertions, 72 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bbfac440d414..f95b3ce98264 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -321,6 +321,12 @@ import java.util.function.Supplier;
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
* @attr ref android.R.styleable#TextView_autoSizeStepGranularity
* @attr ref android.R.styleable#TextView_autoSizePresetSizes
+ * @attr ref android.R.styleable#TextView_textCursorDrawable
+ * @attr ref android.R.styleable#TextView_textSelectHandle
+ * @attr ref android.R.styleable#TextView_textSelectHandleLeft
+ * @attr ref android.R.styleable#TextView_textSelectHandleRight
+ * @attr ref android.R.styleable#TextView_allowUndo
+ * @attr ref android.R.styleable#TextView_enabled
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 9d5f0bcc54d9..ab50ad147107 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -130,6 +130,13 @@ message KeyguardControllerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional bool keyguard_showing = 1;
+ repeated KeyguardOccludedProto keyguard_occluded_states= 2;
+}
+
+message KeyguardOccludedProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 display_id = 1;
optional bool keyguard_occluded = 2;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index c23ad79a52fe..887c1d57c870 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -38,13 +38,13 @@ import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
-import com.android.settingslib.testutils.FragmentTestUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.android.controller.ActivityController;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
@RunWith(SettingsLibRobolectricTestRunner.class)
public class LifecycleTest {
@@ -184,7 +184,7 @@ public class LifecycleTest {
@Test
public void runThroughDialogFragmentLifecycles_shouldObserveEverything() {
final TestDialogFragment fragment = new TestDialogFragment();
- FragmentTestUtils.startFragment(fragment);
+ FragmentController.setupFragment(fragment);
fragment.onCreateOptionsMenu(null, null);
fragment.onPrepareOptionsMenu(null);
@@ -208,7 +208,7 @@ public class LifecycleTest {
@Test
public void runThroughFragmentLifecycles_shouldObserveEverything() {
final TestFragment fragment = new TestFragment();
- FragmentTestUtils.startFragment(fragment);
+ FragmentController.setupFragment(fragment);
fragment.onCreateOptionsMenu(null, null);
fragment.onPrepareOptionsMenu(null);
@@ -248,7 +248,7 @@ public class LifecycleTest {
@Test
public void onOptionItemSelectedShortCircuitsIfAnObserverHandlesTheMenuItem() {
final TestFragment fragment = new TestFragment();
- FragmentTestUtils.startFragment(fragment);
+ FragmentController.setupFragment(fragment);
final OptionItemAccepter accepter = new OptionItemAccepter();
fragment.getLifecycle().addObserver(accepter);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b159b393862a..b8df3c067969 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -342,12 +342,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode != SecurityMode.None
- || !mLockPatternUtils.isLockScreenDisabled(
+ if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser())) {
- showSecurityScreen(securityMode);
- } else {
finish = true;
+ } else {
+ showSecurityScreen(securityMode);
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
index 4f957bfcbbcc..c7ab27ba715d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -67,9 +67,15 @@ public class ContextualButton extends ButtonDispatcher {
}
protected KeyButtonDrawable getNewDrawable() {
- return KeyButtonDrawable.create(getContext(), mIconResId, false /* shadow */);
+ return KeyButtonDrawable.create(getContext().getApplicationContext(), mIconResId,
+ false /* shadow */);
}
+ /**
+ * This context is from the view that could be stale after rotation or config change. To get
+ * correct resources use getApplicationContext() as well.
+ * @return current view context
+ */
protected Context getContext() {
return getCurrentView().getContext();
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 01421c7e65c2..fab967c01086 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -890,6 +890,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
mRemoved = true;
releaseSelfIfNeeded();
+
+ mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId);
}
private void releaseSelfIfNeeded() {
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index ee4e36ff1fd1..cfe282917f3b 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -29,16 +29,20 @@ import static android.view.WindowManager.TRANSIT_UNSET;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
+import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
+import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
+import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -58,19 +62,18 @@ class KeyguardController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
- private final ActivityTaskManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private WindowManagerService mWindowManager;
private boolean mKeyguardShowing;
private boolean mAodShowing;
private boolean mKeyguardGoingAway;
- private boolean mOccluded;
private boolean mDismissalRequested;
- private ActivityRecord mDismissingKeyguardActivity;
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
- private SleepToken mSleepToken;
+ // TODO(b/111955725): Support multiple external displays
private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+ private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
+ private final ActivityTaskManagerService mService;
KeyguardController(ActivityTaskManagerService service,
ActivityStackSupervisor stackSupervisor) {
@@ -87,8 +90,8 @@ class KeyguardController {
* on the given display, false otherwise
*/
boolean isKeyguardOrAodShowing(int displayId) {
- return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway &&
- (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+ return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
+ && !isDisplayOccluded(displayId);
}
/**
@@ -96,8 +99,7 @@ class KeyguardController {
* display, false otherwise
*/
boolean isKeyguardShowing(int displayId) {
- return mKeyguardShowing && !mKeyguardGoingAway &&
- (displayId == DEFAULT_DISPLAY ? !mOccluded : displayId == mSecondaryDisplayShowing);
+ return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
}
/**
@@ -133,6 +135,7 @@ class KeyguardController {
if (showingChanged) {
dismissDockedStackIfNeeded();
setKeyguardGoingAway(false);
+ // TODO(b/113840485): Check usage for non-default display
mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
isKeyguardOrAodShowing(DEFAULT_DISPLAY));
if (keyguardShowing) {
@@ -248,7 +251,8 @@ class KeyguardController {
// already the dismissing activity, in which case we don't allow it to repeatedly dismiss
// Keyguard.
return dismissKeyguard && canDismissKeyguard() && !mAodShowing
- && (mDismissalRequested || r != mDismissingKeyguardActivity);
+ && (mDismissalRequested
+ || getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r);
}
/**
@@ -259,44 +263,16 @@ class KeyguardController {
}
private void visibilitiesUpdated() {
- final boolean lastOccluded = mOccluded;
- final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
- mOccluded = false;
- mDismissingKeyguardActivity = null;
-
+ boolean requestDismissKeyguard = false;
for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
-
- // Only the top activity of the focused stack on the default display may control
- // occluded state.
- if (display.mDisplayId == DEFAULT_DISPLAY
- && mStackSupervisor.isTopDisplayFocusedStack(stack)) {
-
- // A dismissing activity occludes Keyguard in the insecure case for legacy
- // reasons.
- final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
- mOccluded =
- stack.topActivityOccludesKeyguard()
- || (topDismissing != null
- && stack.topRunningActivityLocked() == topDismissing
- && canShowWhileOccluded(
- true /* dismissKeyguard */,
- false /* showWhenLocked */));
- }
-
- if (mDismissingKeyguardActivity == null
- && stack.getTopDismissingKeyguardActivity() != null) {
- mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
- }
- }
- }
- mOccluded |= mWindowManager.isShowingDream();
- if (mOccluded != lastOccluded) {
- handleOccludedChanged();
+ final KeyguardDisplayState state = getDisplay(display.mDisplayId);
+ state.visibilitiesUpdated(this, display);
+ requestDismissKeyguard |= state.mRequestDismissKeyguard;
}
- if (mDismissingKeyguardActivity != lastDismissingKeyguardActivity) {
+
+ // Dismissing Keyguard happens globally using the information from all displays.
+ if (requestDismissKeyguard) {
handleDismissKeyguard();
}
}
@@ -305,7 +281,7 @@ class KeyguardController {
* Called when occluded state changed.
*/
private void handleOccludedChanged() {
- mWindowManager.onKeyguardOccludedChanged(mOccluded);
+ mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
@@ -322,14 +298,13 @@ class KeyguardController {
}
/**
- * Called when somebody might want to dismiss the Keyguard.
+ * Called when somebody wants to dismiss the Keyguard via the flag.
*/
private void handleDismissKeyguard() {
// We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
// reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
// insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
- if (!mOccluded && mDismissingKeyguardActivity != null
- && mWindowManager.isKeyguardSecure()) {
+ if (mWindowManager.isKeyguardSecure()) {
mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
mDismissalRequested = true;
@@ -345,6 +320,10 @@ class KeyguardController {
}
}
+ private boolean isDisplayOccluded(int displayId) {
+ return getDisplay(displayId).mOccluded;
+ }
+
/**
* @return true if Keyguard can be currently dismissed without entering credentials.
*/
@@ -355,12 +334,14 @@ class KeyguardController {
private int resolveOccludeTransit() {
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
- && mOccluded) {
+ // TODO(b/113840485): Handle app transition for individual display.
+ && isDisplayOccluded(DEFAULT_DISPLAY)) {
// Reuse old transit in case we are occluding Keyguard again, meaning that we never
// actually occclude/unocclude Keyguard, but just run a normal transition.
return mBeforeUnoccludeTransit;
- } else if (!mOccluded) {
+ // TODO(b/113840485): Handle app transition for individual display.
+ } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
@@ -371,7 +352,8 @@ class KeyguardController {
}
private void dismissDockedStackIfNeeded() {
- if (mKeyguardShowing && mOccluded) {
+ // TODO(b/113840485): Handle docked stack for individual display.
+ if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
// The lock screen is currently showing, but is occluded by a window that can
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
@@ -386,11 +368,116 @@ class KeyguardController {
}
private void updateKeyguardSleepToken() {
- if (mSleepToken == null && isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
- mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
- } else if (mSleepToken != null && !isKeyguardOrAodShowing(DEFAULT_DISPLAY)) {
- mSleepToken.release();
- mSleepToken = null;
+ for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
+ final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
+ final KeyguardDisplayState state = getDisplay(display.mDisplayId);
+ if (isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken == null) {
+ state.acquiredSleepToken();
+ } else if (!isKeyguardOrAodShowing(display.mDisplayId) && state.mSleepToken != null) {
+ state.releaseSleepToken();
+ }
+ }
+ }
+
+ private KeyguardDisplayState getDisplay(int displayId) {
+ if (mDisplayStates.get(displayId) == null) {
+ mDisplayStates.append(displayId,
+ new KeyguardDisplayState(mService, displayId));
+ }
+ return mDisplayStates.get(displayId);
+ }
+
+ void onDisplayRemoved(int displayId) {
+ if (mDisplayStates.get(displayId) != null) {
+ mDisplayStates.get(displayId).onRemoved();
+ mDisplayStates.remove(displayId);
+ }
+ }
+
+ /** Represents Keyguard state per individual display. */
+ private static class KeyguardDisplayState {
+ private final int mDisplayId;
+ private boolean mOccluded;
+ private ActivityRecord mDismissingKeyguardActivity;
+ private boolean mRequestDismissKeyguard;
+ private final ActivityTaskManagerService mService;
+ private SleepToken mSleepToken;
+
+ KeyguardDisplayState(ActivityTaskManagerService service, int displayId) {
+ mService = service;
+ mDisplayId = displayId;
+ }
+
+ void onRemoved() {
+ mDismissingKeyguardActivity = null;
+ releaseSleepToken();
+ }
+
+ void acquiredSleepToken() {
+ if (mSleepToken == null) {
+ mSleepToken = mService.acquireSleepToken("keyguard", mDisplayId);
+ }
+ }
+
+ void releaseSleepToken() {
+ if (mSleepToken != null) {
+ mSleepToken.release();
+ mSleepToken = null;
+ }
+ }
+
+ void visibilitiesUpdated(KeyguardController controller, ActivityDisplay display) {
+ final boolean lastOccluded = mOccluded;
+ final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
+ mRequestDismissKeyguard = false;
+ mOccluded = false;
+ mDismissingKeyguardActivity = null;
+
+ // Only the top activity of the focused stack on each display may control it's
+ // occluded state.
+ final ActivityStack focusedStack = display.getFocusedStack();
+ if (focusedStack != null) {
+ final ActivityRecord topDismissing =
+ focusedStack.getTopDismissingKeyguardActivity();
+ mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null
+ && focusedStack.topRunningActivityLocked() == topDismissing
+ && controller.canShowWhileOccluded(
+ true /* dismissKeyguard */,
+ false /* showWhenLocked */));
+ if (focusedStack.getTopDismissingKeyguardActivity() != null) {
+ mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+ }
+ mOccluded |= controller.mWindowManager.isShowingDream();
+ }
+
+ // TODO(b/113840485): Handle app transition for individual display.
+ // For now, only default display can change occluded.
+ if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
+ controller.handleOccludedChanged();
+ }
+ if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
+ && mDismissingKeyguardActivity != null
+ && controller.mWindowManager.isKeyguardSecure()) {
+ mRequestDismissKeyguard = true;
+ }
+ }
+
+ void dumpStatus(PrintWriter pw, String prefix) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(prefix);
+ sb.append(" Occluded=").append(mOccluded)
+ .append(" DismissingKeyguardActivity=")
+ .append(mDismissingKeyguardActivity)
+ .append(" at display=")
+ .append(mDisplayId);
+ pw.println(sb.toString());
+ }
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(DISPLAY_ID, mDisplayId);
+ proto.write(KEYGUARD_OCCLUDED, mOccluded);
+ proto.end(token);
}
}
@@ -399,8 +486,7 @@ class KeyguardController {
pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
pw.println(prefix + " mAodShowing=" + mAodShowing);
pw.println(prefix + " mKeyguardGoingAway=" + mKeyguardGoingAway);
- pw.println(prefix + " mOccluded=" + mOccluded);
- pw.println(prefix + " mDismissingKeyguardActivity=" + mDismissingKeyguardActivity);
+ dumpDisplayStates(pw, prefix);
pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
}
@@ -408,7 +494,19 @@ class KeyguardController {
void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
- proto.write(KEYGUARD_OCCLUDED, mOccluded);
+ writeDisplayStatesToProto(proto, KEYGUARD_OCCLUDED_STATES);
proto.end(token);
}
+
+ private void dumpDisplayStates(PrintWriter pw, String prefix) {
+ for (int i = 0; i < mDisplayStates.size(); i++) {
+ mDisplayStates.valueAt(i).dumpStatus(pw, prefix);
+ }
+ }
+
+ private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
+ for (int i = 0; i < mDisplayStates.size(); i++) {
+ mDisplayStates.valueAt(i).writeToProto(proto, fieldId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index deeae26d034c..2557f46ba34b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2828,7 +2828,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Assumes it's safe to show starting windows of launched apps while
// the keyguard is being hidden. This is okay because starting windows never show
// secret information.
- if (mKeyguardOccluded) {
+ // TODO(b/113840485): Occluded may not only happen on default display
+ if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {
windowFlags |= FLAG_SHOW_WHEN_LOCKED;
}
}
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 4a6fe49f2676..1f60b71c3c0f 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -247,8 +247,14 @@ public class AppLaunch extends InstrumentationTestCase {
mIterationCycle = false;
// In the "applaunch.txt" file, trail launches is referenced using
// "TRIAL_LAUNCH"
- String appPkgName = mNameToIntent.get(launch.getApp())
- .getComponent().getPackageName();
+ Intent startIntent = mNameToIntent.get(launch.getApp());
+ if (startIntent == null) {
+ Log.w(TAG, "App does not exist: " + launch.getApp());
+ mResult.putString(mNameToResultKey.get(launch.getApp()),
+ "App does not exist");
+ continue;
+ }
+ String appPkgName = startIntent.getComponent().getPackageName();
if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(VERIFY_FILTER, appPkgName));