Merge "Prevent NPE in ActivityStack#shouldbeVisible." into oc-dev
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
index 69bfeca..323733c 100644
--- a/core/java/android/content/pm/AuxiliaryResolveInfo.java
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -43,13 +43,16 @@
public final String token;
/** The version code of the package */
public final int versionCode;
+ /** An intent to start upon failure to install */
+ public final Intent failureIntent;
/** Create a response for installing an instant application. */
public AuxiliaryResolveInfo(@NonNull InstantAppResolveInfo resolveInfo,
@NonNull IntentFilter orig,
@Nullable String splitName,
@NonNull String token,
- boolean needsPhase2) {
+ boolean needsPhase2,
+ @Nullable Intent failureIntent) {
super(orig);
this.resolveInfo = resolveInfo;
this.packageName = resolveInfo.getPackageName();
@@ -57,12 +60,14 @@
this.token = token;
this.needsPhaseTwo = needsPhase2;
this.versionCode = resolveInfo.getVersionCode();
+ this.failureIntent = failureIntent;
}
/** Create a response for installing a split on demand. */
public AuxiliaryResolveInfo(@NonNull String packageName,
@Nullable String splitName,
- int versionCode) {
+ int versionCode,
+ @Nullable Intent failureIntent) {
super();
this.packageName = packageName;
this.splitName = splitName;
@@ -70,5 +75,6 @@
this.resolveInfo = null;
this.token = null;
this.needsPhaseTwo = false;
+ this.failureIntent = failureIntent;
}
}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a977072..70686b9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -308,6 +308,7 @@
Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+ Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index ccdf5ae..c78c99f 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -705,6 +705,8 @@
}
nativeDetachImage(image);
+ si.clearSurfacePlanes();
+ si.mPlanes = null;
si.setDetached(true);
}
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 349c9cb..2b7309f 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -359,28 +359,14 @@
}
ImageReader prevOwner = (ImageReader) image.getOwner();
- // Only do the image attach for PRIVATE format images for now. Do the image
- // copy for other formats. TODO: use attach for other formats to
- // improve the performance, and fall back to copy when attach/detach
- // fails. Right now, detach is guaranteed to fail as the buffer is
- // locked when ImageReader#acquireNextImage is called. See bug 19962027.
- if (image.getFormat() == ImageFormat.PRIVATE) {
- prevOwner.detachImage(image);
- attachAndQueueInputImage(image);
- // This clears the native reference held by the original owner.
- // When this Image is detached later by this ImageWriter, the
- // native memory won't be leaked.
- image.close();
- return;
- } else {
- Image inputImage = dequeueInputImage();
- inputImage.setTimestamp(image.getTimestamp());
- inputImage.setCropRect(image.getCropRect());
- ImageUtils.imageCopy(image, inputImage);
- image.close();
- image = inputImage;
- ownedByMe = true;
- }
+
+ prevOwner.detachImage(image);
+ attachAndQueueInputImage(image);
+ // This clears the native reference held by the original owner.
+ // When this Image is detached later by this ImageWriter, the
+ // native memory won't be leaked.
+ image.close();
+ return;
}
Rect crop = image.getCropRect();
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index ed5fbcf..b5ea632 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -499,30 +499,23 @@
sp<Surface> surface = ctx->getProducer();
status_t res = OK;
- if (!isFormatOpaque(imageFormat)) {
- // TODO: need implement, see b/19962027
- jniThrowRuntimeException(env,
- "nativeAttachImage for non-opaque image is not implement yet!!!");
- return -1;
- }
-
- if (!isFormatOpaque(ctx->getBufferFormat())) {
+ if (isFormatOpaque(imageFormat) != isFormatOpaque(ctx->getBufferFormat())) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Trying to attach an opaque image into a non-opaque ImageWriter");
+ "Trying to attach an opaque image into a non-opaque ImageWriter, or vice versa");
return -1;
}
// Image is guaranteed to be from ImageReader at this point, so it is safe to
// cast to BufferItem pointer.
- BufferItem* opaqueBuffer = reinterpret_cast<BufferItem*>(nativeBuffer);
- if (opaqueBuffer == NULL) {
+ BufferItem* buffer = reinterpret_cast<BufferItem*>(nativeBuffer);
+ if (buffer == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Image is not initialized or already closed");
return -1;
}
// Step 1. Attach Image
- res = surface->attachBuffer(opaqueBuffer->mGraphicBuffer.get());
+ res = surface->attachBuffer(buffer->mGraphicBuffer.get());
if (res != OK) {
ALOGE("Attach image failed: %s (%d)", strerror(-res), res);
switch (res) {
@@ -559,7 +552,7 @@
}
// Step 3. Queue Image.
- res = anw->queueBuffer(anw.get(), opaqueBuffer->mGraphicBuffer.get(), /*fenceFd*/
+ res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/
-1);
if (res != OK) {
ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
@@ -817,4 +810,3 @@
return (ret1 || ret2);
}
-
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index d5cf1dd..5afa53f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -132,9 +132,6 @@
}
case MESSAGE_EXPAND_PIP: {
mListeners.forEach(l -> l.onPipExpand());
- // Preemptively mark the menu as invisible once we expand the PiP, but don't
- // resize as we will be animating the stack
- onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
break;
}
case MESSAGE_MINIMIZE_PIP: {
@@ -143,9 +140,6 @@
}
case MESSAGE_DISMISS_PIP: {
mListeners.forEach(l -> l.onPipDismiss());
- // Preemptively mark the menu as invisible once we dismiss the PiP, but don't
- // resize as we'll be removing the stack in place
- onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
break;
}
case MESSAGE_SHOW_MENU: {
@@ -308,6 +302,15 @@
}
/**
+ * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
+ * stack and don't want to trigger a resize which can animate the stack in a conflicting way
+ * (ie. when manually expanding or dismissing).
+ */
+ public void hideMenuWithoutResize() {
+ onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
+ }
+
+ /**
* @return the current menu state.
*/
public int getMenuState() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 5121c8d..590e3c6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -77,6 +77,7 @@
private SurfaceFlingerVsyncChoreographer mVsyncChoreographer;
private Handler mHandler;
+ private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
private FlingAnimationUtils mFlingAnimationUtils;
@@ -93,10 +94,12 @@
};
public PipMotionHelper(Context context, IActivityManager activityManager,
- PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) {
+ PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
+ FlingAnimationUtils flingAnimationUtils) {
mContext = context;
mHandler = BackgroundThread.getHandler();
mActivityManager = activityManager;
+ mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFlingAnimationUtils = flingAnimationUtils;
mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(),
@@ -148,6 +151,7 @@
*/
void expandPip(boolean skipAnimation) {
cancelAnimations();
+ mMenuController.hideMenuWithoutResize();
mHandler.post(() -> {
try {
if (skipAnimation) {
@@ -168,6 +172,7 @@
*/
void dismissPip() {
cancelAnimations();
+ mMenuController.hideMenuWithoutResize();
mHandler.post(() -> {
try {
mActivityManager.removeStack(PINNED_STACK_ID);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 9c7e3986..71d3d35 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -191,8 +191,8 @@
mGestures = new PipTouchGesture[] {
mDefaultMovementGesture
};
- mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
- mFlingAnimationUtils);
+ mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mMenuController,
+ mSnapAlgorithm, mFlingAnimationUtils);
mExpandedShortestEdgeSize = context.getResources().getDimensionPixelSize(
R.dimen.pip_expanded_shortest_edge_size);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ff99b19..f37bfac 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3957,6 +3957,11 @@
// OS: O
RUNNING_BACKGROUND_APPS_DIALOG = 944;
+ // FIELD - The delay from the start of the transition until we just call bindApplication on the
+ // client.
+ // OS: O
+ APP_TRANSITION_BIND_APPLICATION_DELAY_MS = 945;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ba48783..6d69915 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6845,6 +6845,7 @@
}
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
+ mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index d4de521..bf7b663 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -10,6 +10,7 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
@@ -78,7 +79,8 @@
private int startResult;
private boolean currentTransitionProcessRunning;
private int windowsDrawnDelayMs;
- private int startingWindowDelayMs;
+ private int startingWindowDelayMs = -1;
+ private int bindApplicationDelayMs = -1;
private int reason = APP_TRANSITION_TIMEOUT;
private boolean loggedWindowsDrawn;
private boolean loggedStartingWindowDrawn;
@@ -296,6 +298,22 @@
}
}
+ /**
+ * Notifies the tracker that we called immediately before we call bindApplication on the client.
+ *
+ * @param app The client into which we'll call bindApplication.
+ */
+ void notifyBindApplication(ProcessRecord app) {
+ for (int i = mStackTransitionInfo.size() - 1; i >= 0; i--) {
+ final StackTransitionInfo info = mStackTransitionInfo.valueAt(i);
+
+ // App isn't attached to record yet, so match with info.
+ if (info.launchedActivity.appInfo == app.info) {
+ info.bindApplicationDelayMs = calculateCurrentDelay();
+ }
+ }
+ }
+
private boolean allStacksWindowsDrawn() {
for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
if (!mStackTransitionInfo.valueAt(index).loggedWindowsDrawn) {
@@ -356,6 +374,10 @@
builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
info.startingWindowDelayMs);
}
+ if (info.bindApplicationDelayMs != -1) {
+ builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
+ info.bindApplicationDelayMs);
+ }
builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
mMetricsLogger.write(builder);
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 18c8b32..ba2c0cd 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -40,6 +40,7 @@
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.CATEGORY_LAUNCHER;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
@@ -61,6 +62,7 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.res.Configuration.EMPTY;
@@ -128,7 +130,6 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Debug;
@@ -1951,13 +1952,9 @@
if (!nowVisible) {
nowVisible = true;
lastVisibleTime = SystemClock.uptimeMillis();
- if (!idle) {
- // Instead of doing the full stop routine here, let's just hide any activities
- // we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
- false /* remove */, true /* processPausingActivities */);
- } else {
- // If this activity was already idle, then we now need to make sure we perform
+ if (idle || mStackSupervisor.isStoppingNoHistoryActivity()) {
+ // If this activity was already idle or there is an activity that must be
+ // stopped immediately after visible, then we now need to make sure we perform
// the full stop of any activities that are waiting to do so. This is because
// we won't do that while they are still waiting for this one to become visible.
final int size = mStackSupervisor.mActivitiesWaitingForVisibleActivity.size();
@@ -1970,6 +1967,11 @@
mStackSupervisor.mActivitiesWaitingForVisibleActivity.clear();
mStackSupervisor.scheduleIdleLocked();
}
+ } else {
+ // Instead of doing the full stop routine here, let's just hide any activities
+ // we now can, and let them stop when the normal idle happens.
+ mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
+ false /* remove */, true /* processPausingActivities */);
}
service.scheduleAppGcsLocked();
}
@@ -2662,6 +2664,15 @@
return true;
}
+ /**
+ * Returns {@code true} if the associated activity has the no history flag set on it.
+ * {@code false} otherwise.
+ */
+ boolean isNoHistory() {
+ return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0
+ || (info.flags & FLAG_NO_HISTORY) != 0;
+ }
+
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
out.attribute(null, ATTR_ID, String.valueOf(createTime));
out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 358d36d..d5b54ca 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3500,6 +3500,23 @@
return mService.mUserController.isCurrentProfileLocked(userId);
}
+ /**
+ * Returns whether a stopping activity is present that should be stopped after visible, rather
+ * than idle.
+ * @return {@code true} if such activity is present. {@code false} otherwise.
+ */
+ boolean isStoppingNoHistoryActivity() {
+ // Activities that are marked as nohistory should be stopped immediately after the resumed
+ // activity has become visible.
+ for (ActivityRecord record : mStoppingActivities) {
+ if (record.isNoHistory()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity,
boolean remove, boolean processPausingActivities) {
ArrayList<ActivityRecord> stops = null;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 1f1aa8e..6d6f33d 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -534,7 +534,8 @@
verificationBundle, userId);
}
return InstantAppResolver.buildEphemeralInstallerIntent(originalIntent,
- callingPackage, verificationBundle, resolvedType, userId, auxiliaryResponse.packageName,
+ auxiliaryResponse.failureIntent, callingPackage, verificationBundle,
+ resolvedType, userId, auxiliaryResponse.packageName,
auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
}
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 93a22494..73cbffd 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -310,7 +310,6 @@
*/
void handleFocusGain(int focusGain) {
try {
- final int oldLoss = mFocusLossReceived;
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -322,9 +321,8 @@
}
if (mFocusLossWasNotified) {
fd.dispatchAudioFocusChange(focusGain, mClientId);
- } else if (oldLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
- mFocusController.unduckPlayers(this);
}
+ mFocusController.unduckPlayers(this);
}
mFocusLossWasNotified = false;
} catch (android.os.RemoteException e) {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 624d8c9..f3c9cbb 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -125,6 +125,7 @@
final String packageName;
final String splitName;
final int versionCode;
+ final Intent failureIntent;
if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
final AuxiliaryResolveInfo instantAppIntentInfo =
InstantAppResolver.filterInstantAppIntent(
@@ -135,18 +136,22 @@
packageName = instantAppIntentInfo.resolveInfo.getPackageName();
splitName = instantAppIntentInfo.splitName;
versionCode = instantAppIntentInfo.resolveInfo.getVersionCode();
+ failureIntent = instantAppIntentInfo.failureIntent;
} else {
packageName = null;
splitName = null;
versionCode = -1;
+ failureIntent = null;
}
} else {
packageName = null;
splitName = null;
versionCode = -1;
+ failureIntent = null;
}
final Intent installerIntent = buildEphemeralInstallerIntent(
requestObj.origIntent,
+ failureIntent,
requestObj.callingPackage,
requestObj.verificationBundle,
requestObj.resolvedType,
@@ -172,7 +177,9 @@
/**
* Builds and returns an intent to launch the instant installer.
*/
- public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent,
+ public static Intent buildEphemeralInstallerIntent(
+ @NonNull Intent origIntent,
+ @NonNull Intent failureIntent,
@NonNull String callingPackage,
@Nullable Bundle verificationBundle,
@NonNull String resolvedType,
@@ -200,22 +207,21 @@
// We have all of the data we need; just start the installer without a second phase
if (!needsPhaseTwo) {
// Intent that is launched if the package couldn't be installed for any reason.
- final Intent failureIntent = new Intent(origIntent);
- failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
- failureIntent.setLaunchToken(token);
- try {
- final IIntentSender failureIntentTarget = ActivityManager.getService()
- .getIntentSender(
- ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
- null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
- new Intent[] { failureIntent },
- new String[] { resolvedType },
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_IMMUTABLE,
- null /*bOptions*/, userId);
- intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE,
- new IntentSender(failureIntentTarget));
- } catch (RemoteException ignore) { /* ignore; same process */ }
+ if (failureIntent != null) {
+ try {
+ final IIntentSender failureIntentTarget = ActivityManager.getService()
+ .getIntentSender(
+ ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+ null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
+ new Intent[] { failureIntent },
+ new String[] { resolvedType },
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE,
+ null /*bOptions*/, userId);
+ intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE,
+ new IntentSender(failureIntentTarget));
+ } catch (RemoteException ignore) { /* ignore; same process */ }
+ }
// Intent that is launched if the package was installed successfully.
final Intent successIntent = new Intent(origIntent);
@@ -248,10 +254,13 @@
private static AuxiliaryResolveInfo filterInstantAppIntent(
List<InstantAppResolveInfo> instantAppResolveInfoList,
- Intent intent, String resolvedType, int userId, String packageName,
+ Intent origIntent, String resolvedType, int userId, String packageName,
InstantAppDigest digest, String token) {
final int[] shaPrefix = digest.getDigestPrefix();
final byte[][] digestBytes = digest.getDigestBytes();
+ final Intent failureIntent = new Intent(origIntent);
+ failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
+ failureIntent.setLaunchToken(token);
// Go in reverse order so we match the narrowest scope first.
for (int i = shaPrefix.length - 1; i >= 0 ; --i) {
for (InstantAppResolveInfo instantAppInfo : instantAppResolveInfoList) {
@@ -271,7 +280,8 @@
}
return new AuxiliaryResolveInfo(instantAppInfo,
new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/,
- null /*splitName*/, token, true /*needsPhase2*/);
+ null /*splitName*/, token, true /*needsPhase2*/,
+ null /*failureIntent*/);
}
// We have a domain match; resolve the filters to see if anything matches.
final PackageManagerService.EphemeralIntentResolver instantAppResolver =
@@ -286,12 +296,12 @@
final AuxiliaryResolveInfo intentInfo =
new AuxiliaryResolveInfo(instantAppInfo,
splitFilters.get(k), instantAppFilter.getSplitName(),
- token, false /*needsPhase2*/);
+ token, false /*needsPhase2*/, failureIntent);
instantAppResolver.addFilter(intentInfo);
}
}
List<AuxiliaryResolveInfo> matchedResolveInfoList = instantAppResolver.queryIntent(
- intent, resolvedType, false /*defaultOnly*/, userId);
+ origIntent, resolvedType, false /*defaultOnly*/, userId);
if (!matchedResolveInfoList.isEmpty()) {
if (DEBUG_EPHEMERAL) {
final AuxiliaryResolveInfo info = matchedResolveInfoList.get(0);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 121ae07..55285c8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6702,7 +6702,7 @@
final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
info.activityInfo.packageName, info.activityInfo.splitName,
- info.activityInfo.applicationInfo.versionCode);
+ info.activityInfo.applicationInfo.versionCode, null /*failureIntent*/);
// make sure this resolver is the default
installerInfo.isDefault = true;
installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -7375,7 +7375,7 @@
final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
info.serviceInfo.packageName, info.serviceInfo.splitName,
- info.serviceInfo.applicationInfo.versionCode);
+ info.serviceInfo.applicationInfo.versionCode, null /*failureIntent*/);
// make sure this resolver is the default
installerInfo.isDefault = true;
installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -7496,7 +7496,7 @@
final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
info.providerInfo.packageName, info.providerInfo.splitName,
- info.providerInfo.applicationInfo.versionCode);
+ info.providerInfo.applicationInfo.versionCode, null /*failureIntent*/);
// make sure this resolver is the default
installerInfo.isDefault = true;
installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b27d6c4..92d26cb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2948,27 +2948,29 @@
}
// Don't include wallpaper in bounds calculation
- if (!mutableIncludeFullDisplay.value && includeDecor) {
- final TaskStack stack = w.getStack();
- if (stack != null) {
- stack.getBounds(frame);
- }
+ if (!w.mIsWallpaper && !mutableIncludeFullDisplay.value) {
+ if (includeDecor) {
+ final TaskStack stack = w.getStack();
+ if (stack != null) {
+ stack.getBounds(frame);
+ }
- // We want to screenshot with the exact bounds of the surface of the app. Thus,
- // intersect it with the frame.
- frame.intersect(w.mFrame);
- }else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
- final Rect wf = w.mFrame;
- final Rect cr = w.mContentInsets;
- int left = wf.left + cr.left;
- int top = wf.top + cr.top;
- int right = wf.right - cr.right;
- int bottom = wf.bottom - cr.bottom;
- frame.union(left, top, right, bottom);
- w.getVisibleBounds(stackBounds);
- if (!Rect.intersects(frame, stackBounds)) {
- // Set frame empty if there's no intersection.
- frame.setEmpty();
+ // We want to screenshot with the exact bounds of the surface of the app. Thus,
+ // intersect it with the frame.
+ frame.intersect(w.mFrame);
+ } else {
+ final Rect wf = w.mFrame;
+ final Rect cr = w.mContentInsets;
+ int left = wf.left + cr.left;
+ int top = wf.top + cr.top;
+ int right = wf.right - cr.right;
+ int bottom = wf.bottom - cr.bottom;
+ frame.union(left, top, right, bottom);
+ w.getVisibleBounds(stackBounds);
+ if (!Rect.intersects(frame, stackBounds)) {
+ // Set frame empty if there's no intersection.
+ frame.setEmpty();
+ }
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 03ef319..b34fcdc 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -22,6 +22,7 @@
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.REQUEST_REGISTERED;
import static org.junit.Assert.assertEquals;
@@ -464,11 +465,10 @@
}
/**
- * Verify the handler passed in to startLocalOnlyHotspot is correctly used for callbacks when a
- * null WifiConfig is returned.
+ * Verify callback triggered from startLocalOnlyHotspot with an incompatible mode failure.
*/
@Test
- public void testLocalOnlyHotspotCallbackFullOnNullConfig() throws Exception {
+ public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
.thenReturn(ERROR_INCOMPATIBLE_MODE);
@@ -481,6 +481,22 @@
}
/**
+ * Verify callback triggered from startLocalOnlyHotspot with a tethering disallowed failure.
+ */
+ @Test
+ public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
+ TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
+ when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
+ .thenReturn(ERROR_TETHERING_DISALLOWED);
+ mWifiManager.startLocalOnlyHotspot(callback, mHandler);
+ mLooper.dispatchAll();
+ assertEquals(ERROR_TETHERING_DISALLOWED, callback.mFailureReason);
+ assertFalse(callback.mOnStartedCalled);
+ assertFalse(callback.mOnStoppedCalled);
+ assertEquals(null, callback.mRes);
+ }
+
+ /**
* Verify a SecurityException resulting from an application without necessary permissions will
* bubble up through the call to start LocalOnlyHotspot and will not trigger other callbacks.
*/