Merge "Fix contrast enforcement for RemoteInputView" into nyc-dev
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 3ae9e12..fae0400 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -53,7 +53,6 @@
libutils \
liblog \
libbinder \
- libnativeloader \
libandroid_runtime \
$(app_process_common_shared_libs) \
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 7590325..2e02382 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -21,7 +21,6 @@
#include <cutils/properties.h>
#include <cutils/trace.h>
#include <android_runtime/AndroidRuntime.h>
-#include <nativeloader/native_loader.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
namespace android {
@@ -305,7 +304,6 @@
}
if (zygote) {
- InitializeNativeLoader();
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 4db4567..aeda7a2 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1748,7 +1748,7 @@
*
* @hide
*/
- public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
+ public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
@@ -1765,7 +1765,7 @@
*
* @hide
*/
- public void notifyChange(Uri uri, ContentObserver observer, @NotifyFlags int flags,
+ public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
@UserIdInt int userHandle) {
try {
getContentService().notifyChange(
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0c79312..03f83d6 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -222,7 +222,7 @@
in String installerPackageName,
int userId);
- void finishPackageInstall(int token);
+ void finishPackageInstall(int token, boolean didLaunch);
void setInstallerPackageName(in String targetPackage, in String installerPackageName);
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 9793cdb..f4237d2 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -13,28 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#define LOG_TAG "SensorManager"
-#include <map>
+#include "JNIHelp.h"
+#include "android_os_MessageQueue.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
#include <ScopedUtfChars.h>
#include <ScopedLocalRef.h>
-
+#include <android_runtime/AndroidRuntime.h>
+#include <gui/Sensor.h>
+#include <gui/SensorEventQueue.h>
+#include <gui/SensorManager.h>
#include <utils/Log.h>
#include <utils/Looper.h>
#include <utils/Vector.h>
-#include <gui/Sensor.h>
-#include <gui/SensorManager.h>
-#include <gui/SensorEventQueue.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_os_MessageQueue.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include "core_jni_helpers.h"
+#include <endian.h> // htobe64
+#include <map>
namespace {
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index feb8052..520ebe5 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -129,6 +129,10 @@
* <strong>Note:</strong> This class takes ownership of the passed in file descriptor
* and is responsible for closing it when the renderer is closed.
* </p>
+ * <p>
+ * If the file is from an untrusted source it is recommended to run the renderer in a separate,
+ * isolated process with minimal permissions to limit the impact of security exploits.
+ * </p>
*
* @param input Seekable file descriptor to read from.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index a026a96..5e9a8bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -56,15 +56,6 @@
private final Rect mClipBounds = new Rect();
private final int mMinContractedHeight;
private final int mNotificationContentMarginEnd;
- private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- selectLayout(false /* animate */, false /* force */);
- }
- };
-
private View mContractedChild;
private View mExpandedChild;
@@ -119,6 +110,7 @@
private int mTransformationStartVisibleType;
private boolean mUserExpanding;
private int mSingleLineWidthIndention;
+ private boolean mForceSelectNextLayout = true;
private PendingIntent mPreviousExpandedRemoteInputIntent;
private PendingIntent mPreviousHeadsUpRemoteInputIntent;
@@ -270,6 +262,8 @@
super.onLayout(changed, left, top, right, bottom);
updateClipping();
invalidateOutline();
+ selectLayout(false /* animate */, mForceSelectNextLayout /* force */);
+ mForceSelectNextLayout = false;
}
@Override
@@ -317,44 +311,35 @@
public void setContractedChild(View child) {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
- mContractedChild.removeOnLayoutChangeListener(mLayoutUpdater);
removeView(mContractedChild);
}
addView(child);
mContractedChild = child;
- mContractedChild.addOnLayoutChangeListener(mLayoutUpdater);
mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
- selectLayout(false /* animate */, true /* force */);
mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
}
public void setExpandedChild(View child) {
if (mExpandedChild != null) {
mExpandedChild.animate().cancel();
- mExpandedChild.removeOnLayoutChangeListener(mLayoutUpdater);
removeView(mExpandedChild);
}
addView(child);
mExpandedChild = child;
- mExpandedChild.addOnLayoutChangeListener(mLayoutUpdater);
mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
- selectLayout(false /* animate */, true /* force */);
}
public void setHeadsUpChild(View child) {
if (mHeadsUpChild != null) {
mHeadsUpChild.animate().cancel();
- mHeadsUpChild.removeOnLayoutChangeListener(mLayoutUpdater);
removeView(mHeadsUpChild);
}
addView(child);
mHeadsUpChild = child;
- mHeadsUpChild.addOnLayoutChangeListener(mLayoutUpdater);
mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
- selectLayout(false /* animate */, true /* force */);
}
@Override
@@ -408,7 +393,8 @@
updateBackgroundColor(true /* animate */);
}
if (mTransformationStartVisibleType != UNDEFINED
- && mVisibleType != mTransformationStartVisibleType) {
+ && mVisibleType != mTransformationStartVisibleType
+ && getViewForVisibleType(mTransformationStartVisibleType) != null) {
final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType);
final TransformableView hiddenView = getTransformableViewForVisibleType(
mTransformationStartVisibleType);
@@ -501,26 +487,66 @@
}
if (mUserExpanding) {
updateContentTransformation();
- return;
- }
- int visibleType = calculateVisibleType();
- if (visibleType != mVisibleType || force) {
+ } else {
+ int visibleType = calculateVisibleType();
+ if (visibleType != mVisibleType || force) {
View visibleView = getViewForVisibleType(visibleType);
if (visibleView != null) {
visibleView.setVisibility(VISIBLE);
transferRemoteInputFocus(visibleType);
}
- if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
- || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
- || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
- || visibleType == VISIBLE_TYPE_CONTRACTED)) {
- animateToVisibleType(visibleType);
- } else {
- updateViewVisibilities(visibleType);
+ if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
+ || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
+ || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
+ || visibleType == VISIBLE_TYPE_CONTRACTED)) {
+ animateToVisibleType(visibleType);
+ } else {
+ updateViewVisibilities(visibleType);
+ }
+ mVisibleType = visibleType;
+ updateBackgroundColor(animate);
}
- mVisibleType = visibleType;
- updateBackgroundColor(animate);
+ }
+ if (mForceSelectNextLayout) {
+ forceUpdateVisibilities();
+ }
+ }
+
+ private void forceUpdateVisibilities() {
+ boolean contractedVisible = mVisibleType == VISIBLE_TYPE_CONTRACTED
+ || mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED;
+ boolean expandedVisible = mVisibleType == VISIBLE_TYPE_EXPANDED
+ || mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED;
+ boolean headsUpVisible = mVisibleType == VISIBLE_TYPE_HEADSUP
+ || mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP;
+ boolean singleLineVisible = mVisibleType == VISIBLE_TYPE_SINGLELINE
+ || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE;
+ if (!contractedVisible) {
+ mContractedChild.setVisibility(View.INVISIBLE);
+ } else {
+ mContractedWrapper.setVisible(true);
+ }
+ if (mExpandedChild != null) {
+ if (!expandedVisible) {
+ mExpandedChild.setVisibility(View.INVISIBLE);
+ } else {
+ mExpandedWrapper.setVisible(true);
+ }
+ }
+ if (mHeadsUpChild != null) {
+ if (!headsUpVisible) {
+ mHeadsUpChild.setVisibility(View.INVISIBLE);
+ } else {
+ mHeadsUpWrapper.setVisible(true);
+ }
+ }
+ if (mSingleLineView != null) {
+ if (!singleLineVisible) {
+ mSingleLineView.setVisibility(View.INVISIBLE);
+ } else {
+ mSingleLineView.setVisible(true);
+ }
}
}
@@ -558,7 +584,7 @@
private void animateToVisibleType(int visibleType) {
final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
- if (shownView == hiddenView) {
+ if (shownView == hiddenView || hiddenView == null) {
shownView.setVisible(true);
return;
}
@@ -647,8 +673,9 @@
height = mContentHeight;
}
int expandedVisualType = getVisualTypeForHeight(height);
- int collapsedVisualType = getVisualTypeForHeight(
- mContainingNotification.getCollapsedHeight());
+ int collapsedVisualType = mIsChildInGroup && !isGroupExpanded()
+ ? VISIBLE_TYPE_SINGLELINE
+ : getVisualTypeForHeight(mContainingNotification.getCollapsedHeight());
return mTransformationStartVisibleType == collapsedVisualType
? expandedVisualType
: collapsedVisualType;
@@ -762,7 +789,7 @@
mHeadsUpWrapper.notifyContentUpdated(entry.notification);
}
updateShowingLegacyBackground();
- selectLayout(false /* animate */, true /* force */);
+ mForceSelectNextLayout = true;
setDark(mDark, false /* animate */, 0 /* delay */);
mPreviousExpandedRemoteInputIntent = null;
mPreviousHeadsUpRemoteInputIntent = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index f04fe5e..8207215 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -100,8 +100,17 @@
boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0;
boolean transformScale = transformScale();
// lets animate the positions correctly
- if (transformationAmount == 0.0f) {
- int[] otherPosition = otherState.getLocationOnScreen();
+ if (transformationAmount == 0.0f
+ || transformX && getTransformationStartX() == UNDEFINED
+ || transformY && getTransformationStartY() == UNDEFINED
+ || transformScale && getTransformationStartScaleX() == UNDEFINED
+ || transformScale && getTransformationStartScaleY() == UNDEFINED) {
+ int[] otherPosition;
+ if (transformationAmount != 0.0f) {
+ otherPosition = otherState.getLaidOutLocationOnScreen();
+ } else {
+ otherPosition = otherState.getLocationOnScreen();
+ }
int[] ownStablePosition = getLaidOutLocationOnScreen();
if (customTransformation == null
|| !customTransformation.initTransformation(this, otherState)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 0fdd99f..f3033cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -44,6 +44,8 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
@@ -127,10 +129,14 @@
mEditText.mShowImeOnInputConnection = false;
mController.remoteInputSent(mEntry);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_SEND,
+ mEntry.notification.getPackageName());
try {
mPendingIntent.send(mContext, 0, fillInIntent);
} catch (PendingIntent.CanceledException e) {
Log.i(TAG, "Unable to send remote input result", e);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_FAIL,
+ mEntry.notification.getPackageName());
}
}
@@ -165,6 +171,8 @@
mController.removeRemoteInput(mEntry);
mEntry.remoteInputText = mEditText.getText();
setVisibility(INVISIBLE);
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
+ mEntry.notification.getPackageName());
}
@Override
@@ -198,6 +206,9 @@
}
public void focus() {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_OPEN,
+ mEntry.notification.getPackageName());
+
setVisibility(VISIBLE);
mController.addRemoteInput(mEntry);
mEditText.setInnerFocusable(true);
@@ -252,6 +263,7 @@
findScrollContainer();
if (mScrollContainer != null) {
mScrollContainer.requestDisallowLongPress();
+ mScrollContainer.requestDisallowDismiss();
}
}
return super.onInterceptTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 9603e81..0a4dce8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -232,6 +232,7 @@
* animating.
*/
private boolean mOnlyScrollingInThisMotion;
+ private boolean mDisallowDismissInThisMotion;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
@@ -1031,7 +1032,8 @@
if (!mIsBeingDragged
&& !mExpandingNotification
&& !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion) {
+ && !mOnlyScrollingInThisMotion
+ && !mDisallowDismissInThisMotion) {
horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
}
return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
@@ -2013,7 +2015,8 @@
if (!mIsBeingDragged
&& !mExpandingNotification
&& !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion) {
+ && !mOnlyScrollingInThisMotion
+ && !mDisallowDismissInThisMotion) {
swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
}
return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
@@ -2041,6 +2044,7 @@
mExpandedInThisMotion = false;
mOnlyScrollingInThisMotion = !mScroller.isFinished();
mDisallowScrollingInThisMotion = false;
+ mDisallowDismissInThisMotion = false;
mTouchIsClick = true;
mInitialTouchX = ev.getX();
mInitialTouchY = ev.getY();
@@ -2705,6 +2709,11 @@
removeLongPressCallback();
}
+ @Override
+ public void requestDisallowDismiss() {
+ mDisallowDismissInThisMotion = true;
+ }
+
public void removeLongPressCallback() {
mSwipeHelper.removeLongPressCallback();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
index a35465e..64efa69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
@@ -33,4 +33,9 @@
* Request that the view is made visible by scrolling to it.
*/
void scrollTo(View v);
+
+ /**
+ * Request that the view does not dismiss for the current touch.
+ */
+ void requestDisallowDismiss();
}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 2f79079..a3ea592 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -22,22 +22,28 @@
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackupDataOutput;
import android.content.Context;
+import android.graphics.Rect;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.system.Os;
import android.util.Slog;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
public class WallpaperBackupAgent extends BackupAgent {
private static final String TAG = "WallpaperBackup";
private static final boolean DEBUG = false;
// NB: must be kept in sync with WallpaperManagerService but has no
- // compile-time visiblity.
+ // compile-time visibility.
// Target filenames within the system's wallpaper directory
static final String WALLPAPER = "wallpaper_orig";
@@ -107,11 +113,7 @@
}
// We use the default onRestoreFile() implementation that will recreate our stage files,
- // then postprocess in onRestoreFinished() to move them on top of the live data.
- //
- // NOTE: this relies on our local files dir being on the same filesystem as the live
- // system wallpaper data. If this is not the case then an actual copy operation will
- // be needed.
+ // then post-process in onRestoreFinished() to apply the new wallpaper.
@Override
public void onRestoreFinished() {
if (DEBUG) {
@@ -125,19 +127,25 @@
// to back up the original image on the source device.
if (imageStage.exists()) {
if (DEBUG) {
- Slog.v(TAG, "Got restored wallpaper; renaming into place");
+ Slog.v(TAG, "Got restored wallpaper; applying");
}
- // Rename the image file into place last because that is the trigger for
- // the wallpaper observer to generate a new crop/scale
- Os.rename(infoStage.getCanonicalPath(), mWallpaperInfo.getCanonicalPath());
- Os.rename(imageStage.getCanonicalPath(), mWallpaperFile.getCanonicalPath());
+
+ // Parse the restored info file to find the crop hint. Note that this currently
+ // relies on a priori knowledge of the wallpaper info file schema.
+ Rect cropHint = parseCropHint(infoStage);
+ if (cropHint != null) {
+ if (DEBUG) {
+ Slog.v(TAG, "Restored crop hint " + cropHint + "; now writing data");
+ }
+ WallpaperManager wm = getSystemService(WallpaperManager.class);
+ try (FileInputStream in = new FileInputStream(imageStage)) {
+ wm.setStream(in, cropHint, true, WallpaperManager.FLAG_SYSTEM);
+ } finally {} // auto-closes 'in'
+ }
}
} catch (Exception e) {
Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
- mWm.clearWallpaper(WallpaperManager.FLAG_SYSTEM, UserHandle.USER_SYSTEM);
} finally {
- // These "should" not exist because of the renames, but make sure
- // in case of errors/exceptions/etc.
if (DEBUG) {
Slog.v(TAG, "Removing restore stage files");
}
@@ -146,8 +154,41 @@
}
}
+ private Rect parseCropHint(File wallpaperInfo) {
+ Rect cropHint = new Rect();
+ try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+
+ int type;
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ String tag = parser.getName();
+ if ("wp".equals(tag)) {
+ cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+ cropHint.top = getAttributeInt(parser, "cropTop", 0);
+ cropHint.right = getAttributeInt(parser, "cropRight", 0);
+ cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+ } catch (Exception e) {
+ // Whoops; can't process the info file at all. Report failure.
+ Slog.w(TAG, "Failed to parse restored metadata: " + e.getMessage());
+ return null;
+ }
+
+ return cropHint;
+ }
+
+ private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
+ final String value = parser.getAttributeValue(null, name);
+ return (value == null) ? defValue : Integer.parseInt(value);
+ }
+
//
- // Key/value API: abstract, so required, but not used
+ // Key/value API: abstract, therefore required; but not used
//
@Override
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 7b3fd66..f49235c 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2169,6 +2169,24 @@
// User blacklisted an app for Data Saver mode; action pass package name of app.
ACTION_DATA_SAVER_BLACKLIST = 396;
+ // User opened a remote input view associated with a notification. Passes package name of app
+ // that posted the notification. Note that this can also happen transiently during notification
+ // reinflation.
+ ACTION_REMOTE_INPUT_OPEN = 397;
+
+ // User attempt to send data through a remote input view associated with a notification.
+ // Passes package name of app that posted the notification. May succeed or fail.
+ ACTION_REMOTE_INPUT_SEND = 398;
+
+ // Failed attempt to send data through a remote input view associated with a
+ // notification. Passes package name of app that posted the notification.
+ ACTION_REMOTE_INPUT_FAIL = 399;
+
+ // User closed a remote input view associated with a notification. Passes package name of app
+ // that posted the notification. Note that this can also happen transiently during notification
+ // reinflation.
+ ACTION_REMOTE_INPUT_CLOSE = 400;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6288b56..95f9e2d 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -7706,6 +7706,11 @@
// when we're finished.
private int mPmToken;
+ // When this is restore-during-install, we need to tell the package manager
+ // whether we actually launched the app, because this affects notifications
+ // around externally-visible state transitions.
+ private boolean mDidLaunch;
+
// Is this a whole-system restore, i.e. are we establishing a new ancestral
// dataset to base future restore-at-install operations from?
private boolean mIsSystemRestore;
@@ -7769,6 +7774,7 @@
mTargetPackage = targetPackage;
mIsSystemRestore = isFullSystemRestore;
mFinished = false;
+ mDidLaunch = false;
if (targetPackage != null) {
// Single package restore
@@ -8149,6 +8155,9 @@
return;
}
+ // Whatever happens next, we've launched the target app now; remember that.
+ mDidLaunch = true;
+
// And then finally start the restore on this agent
try {
initiateOneRestore(mCurrentPackage, metaInfo.versionCode);
@@ -8430,6 +8439,10 @@
// Now we're really done with this one too
IoUtils.closeQuietly(mEnginePipes[0]);
+ // In all cases we want to remember whether we launched
+ // the target app as part of our work so far.
+ mDidLaunch = (mEngine.getAgent() != null);
+
// If we hit a transport-level error, we are done with everything;
// if we hit an agent error we just go back to running the queue.
if (status == BackupTransport.TRANSPORT_OK) {
@@ -8522,7 +8535,7 @@
if (mPmToken > 0) {
if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
try {
- mPackageManagerBinder.finishPackageInstall(mPmToken);
+ mPackageManagerBinder.finishPackageInstall(mPmToken, mDidLaunch);
} catch (RemoteException e) { /* can't happen */ }
} else {
// We were invoked via an active restore session, not by the Package
@@ -9682,7 +9695,7 @@
// Manager to proceed with the post-install handling for this package.
if (DEBUG) Slog.v(TAG, "Finishing install immediately");
try {
- mPackageManagerBinder.finishPackageInstall(token);
+ mPackageManagerBinder.finishPackageInstall(token, false);
} catch (RemoteException e) { /* can't happen */ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index ac5c4ae..5096b35 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -192,11 +192,13 @@
}
}
- if (!mPendingIntents.isEmpty()) {
- pw.println();
- pw.println("Pending intents:");
- for (PendingIntent pi : mPendingIntents) {
- pw.println(pi.toString());
+ synchronized (mPendingIntents) {
+ if (!mPendingIntents.isEmpty()) {
+ pw.println();
+ pw.println("Pending intents:");
+ for (PendingIntent pi : mPendingIntents) {
+ pw.println(pi.toString());
+ }
}
}
@@ -327,9 +329,9 @@
result[i++] = e;
}
}
- }
- reference.setValue(mLastEventReference);
+ reference.setValue(mLastEventReference);
+ }
return result;
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 03eb019..2103cce 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -352,6 +352,10 @@
if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
+ " from observer " + observer + ", flags " + Integer.toHexString(flags));
+ if (uri == null) {
+ throw new NullPointerException("Uri must not be null");
+ }
+
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final int callingUserHandle = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 50b8670..649a27c 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -22,9 +22,7 @@
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.IOtaDexopt;
-import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.os.Environment;
import android.os.RemoteException;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4b0eeed..89dc4fb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -498,8 +498,8 @@
public static final int REASON_LAST = REASON_FORCED_DEXOPT;
- // Special String to skip shared libraries check during compilation.
- private static final String SPECIAL_SHARED_LIBRARY = "&";
+ /** Special library name that skips shared libraries check during compilation. */
+ private static final String SKIP_SHARED_LIBRARY_CHECK = "&";
final ServiceThread mHandlerThread;
@@ -1570,6 +1570,7 @@
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
PostInstallData data = mRunningInstalls.get(msg.arg1);
+ final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
if (data != null) {
@@ -1584,7 +1585,8 @@
// Handle the parent package
handlePackagePostInstall(parentRes, grantPermissions, killApp,
- grantedPermissions, args.observer);
+ grantedPermissions, didRestore, args.installerPackageName,
+ args.observer);
// Handle the child packages
final int childCount = (parentRes.addedChildPackages != null)
@@ -1592,7 +1594,8 @@
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
handlePackagePostInstall(childRes, grantPermissions, killApp,
- grantedPermissions, args.observer);
+ grantedPermissions, false, args.installerPackageName,
+ args.observer);
}
// Log tracing if needed
@@ -1788,6 +1791,7 @@
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, String[] grantedPermissions,
+ boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver) {
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
// Send the removed broadcasts
@@ -1872,6 +1876,14 @@
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUsers);
+ } else if (launchedForRestore && !isSystemApp(res.pkg)) {
+ // First-install and we did a restore, so we're responsible for the
+ // first-launch broadcast.
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Post-restore of " + packageName
+ + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers));
+ }
+ sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers);
}
// Send broadcast package appeared if forward locked/external for all users
@@ -2336,7 +2348,7 @@
dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
getCompilerFilterForReason(REASON_SHARED_APK),
StorageManager.UUID_PRIVATE_INTERNAL,
- SPECIAL_SHARED_LIBRARY);
+ SKIP_SHARED_LIBRARY_CHECK);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -11723,7 +11735,7 @@
}
@Override
- public void finishPackageInstall(int token) {
+ public void finishPackageInstall(int token, boolean didLaunch) {
enforceSystemOrRoot("Only the system is allowed to finish installs");
if (DEBUG_INSTALL) {
@@ -11731,7 +11743,7 @@
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- final Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+ final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
mHandler.sendMessage(msg);
}
@@ -12060,6 +12072,54 @@
});
}
+ /**
+ * Callback from PackageSettings whenever an app is first transitioned out of the
+ * 'stopped' state. Normally we just issue the broadcast, but we can't do that if
+ * the app was "launched" for a restoreAtInstall operation. Therefore we check
+ * here whether the app is the target of an ongoing install, and only send the
+ * broadcast immediately if it is not in that state. If it *is* undergoing a restore,
+ * the first-launch broadcast will be sent implicitly on that basis in POST_INSTALL
+ * handling.
+ */
+ void notifyFirstLaunch(final String pkgName, final String installerPackage, final int userId) {
+ // Serialize this with the rest of the install-process message chain. In the
+ // restore-at-install case, this Runnable will necessarily run before the
+ // POST_INSTALL message is processed, so the contents of mRunningInstalls
+ // are coherent. In the non-restore case, the app has already completed install
+ // and been launched through some other means, so it is not in a problematic
+ // state for observers to see the FIRST_LAUNCH signal.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < mRunningInstalls.size(); i++) {
+ final PostInstallData data = mRunningInstalls.valueAt(i);
+ if (pkgName.equals(data.res.pkg.applicationInfo.packageName)) {
+ // right package; but is it for the right user?
+ for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
+ if (userId == data.res.newUsers[uIndex]) {
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Package " + pkgName
+ + " being restored so deferring FIRST_LAUNCH");
+ }
+ return;
+ }
+ }
+ }
+ }
+ // didn't find it, so not being restored
+ if (DEBUG_BACKUP) {
+ Slog.i(TAG, "Package " + pkgName + " sending normal FIRST_LAUNCH");
+ }
+ sendFirstLaunchBroadcast(pkgName, installerPackage, new int[] {userId});
+ }
+ });
+ }
+
+ private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
+ installerPkg, null, userIds);
+ }
+
private abstract class HandlerParams {
private static final int MAX_RETRIES = 4;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f20a36e..1040f85 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4133,7 +4133,7 @@
return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
}
- boolean setPackageStoppedStateLPw(PackageManagerService yucky, String packageName,
+ boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
boolean stopped, boolean allowedByPermission, int uid, int userId) {
int appId = UserHandle.getAppId(uid);
final PackageSetting pkgSetting = mPackages.get(packageName);
@@ -4158,9 +4158,7 @@
// pkgSetting.pkg.mSetStopped = stopped;
if (pkgSetting.getNotLaunched(userId)) {
if (pkgSetting.installerPackageName != null) {
- yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
- pkgSetting.name, null, 0,
- pkgSetting.installerPackageName, null, new int[] {userId});
+ pm.notifyFirstLaunch(pkgSetting.name, pkgSetting.installerPackageName, userId);
}
pkgSetting.setNotLaunched(false, userId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6a20edb..534c661 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6290,9 +6290,11 @@
+ maxLayer + " appToken=" + appToken);
for (int i = 0; i < windows.size(); i++) {
WindowState win = windows.get(i);
+ WindowSurfaceController controller = win.mWinAnimator.mSurfaceController;
Slog.i(TAG_WM, win + ": " + win.mLayer
+ " animLayer=" + win.mWinAnimator.mAnimLayer
- + " surfaceLayer=" + win.mWinAnimator.mSurfaceController.getLayer());
+ + " surfaceLayer=" + ((controller == null)
+ ? "null" : controller.getLayer()));
}
}