Merge "Add support for --replace-version to aapt2"
diff --git a/api/current.txt b/api/current.txt
index 9d8db31..7787c1bfc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -70142,7 +70142,7 @@
method public java.util.regex.Matcher reset();
method public java.util.regex.Matcher reset(java.lang.CharSequence);
method public int start();
- method public int start(int) throws java.lang.IllegalStateException;
+ method public int start(int);
method public int start(java.lang.String);
method public java.util.regex.MatchResult toMatchResult();
method public java.util.regex.Matcher useAnchoringBounds(boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index 54604a5..79a8d44 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -244,6 +244,7 @@
package android.content.pm {
public class ActivityInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable {
+ method public static boolean isTranslucentOrFloating(android.content.res.TypedArray);
field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 091268e..5268ba2 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -141,10 +141,14 @@
LOCAL_MODULE_CLASS := EXECUTABLES
-# Enable sanitizer and allow very verbose printing on eng builds
+# Enable sanitizer ONLY on eng builds.
ifeq ($(TARGET_BUILD_VARIANT),eng)
LOCAL_CLANG := true
LOCAL_SANITIZE := address
+endif
+
+# Add a flag to enable stats log printing from statsd on debug builds.
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += \
-DVERY_VERBOSE_PRINTING
endif
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index e7f1caf..1378ce5 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -152,7 +152,7 @@
if (is_create) {
mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
} else {
- mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
+ mUidMap->removeIsolatedUid(isolated_uid);
}
} else {
ALOGE("Failed to parse uid in the isolated uid change event.");
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ab9c7e8..ca3786a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -1484,6 +1484,7 @@
message IsolatedUidChanged {
// The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
// NOTE: DO NOT annotate uid field in this atom. This atom is specially handled in statsd.
+ // This field is ignored when event == REMOVED.
optional int32 parent_uid = 1;
optional int32 isolated_uid = 2;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index fff909c..be94725 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -272,7 +272,7 @@
mIsolatedUidMap[isolatedUid] = parentUid;
}
-void UidMap::removeIsolatedUid(int isolatedUid, int parentUid) {
+void UidMap::removeIsolatedUid(int isolatedUid) {
lock_guard<mutex> lock(mIsolatedMutex);
auto it = mIsolatedUidMap.find(isolatedUid);
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 5e42cd1..514eec7 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -119,7 +119,7 @@
void OnConfigRemoved(const ConfigKey& key);
void assignIsolatedUid(int isolatedUid, int parentUid);
- void removeIsolatedUid(int isolatedUid, int parentUid);
+ void removeIsolatedUid(int isolatedUid);
// Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in.
virtual int getHostUidOrSelf(int uid) const;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index b04d0f9..67d60fa 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -261,6 +261,7 @@
Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mPendingConfiguration:Landroid/content/res/Configuration;
Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->mProviderRefCountMap:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mResourcePackages:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mResourcesManager:Landroid/app/ResourcesManager;
Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap;
@@ -906,9 +907,14 @@
Landroid/app/SearchManager;->launchAssist(Landroid/os/Bundle;)V
Landroid/app/SearchManager;->mSearchDialog:Landroid/app/SearchDialog;
Landroid/app/SearchManager;->startSearch(Ljava/lang/String;ZLandroid/content/ComponentName;Landroid/os/Bundle;ZLandroid/graphics/Rect;)V
+Landroid/app/servertransaction/ActivityResultItem;->mResultInfoList:Ljava/util/List;
+Landroid/app/servertransaction/ClientTransaction;->getActivityToken()Landroid/os/IBinder;
+Landroid/app/servertransaction/ClientTransaction;->getCallbacks()Ljava/util/List;
+Landroid/app/servertransaction/ClientTransaction;->getLifecycleStateRequest()Landroid/app/servertransaction/ActivityLifecycleItem;
Landroid/app/servertransaction/ClientTransaction;->mActivityCallbacks:Ljava/util/List;
Landroid/app/servertransaction/LaunchActivityItem;->mInfo:Landroid/content/pm/ActivityInfo;
Landroid/app/servertransaction/LaunchActivityItem;->mIntent:Landroid/content/Intent;
+Landroid/app/servertransaction/NewIntentItem;->mIntents:Ljava/util/List;
Landroid/app/Service;->attach(Landroid/content/Context;Landroid/app/ActivityThread;Ljava/lang/String;Landroid/os/IBinder;Landroid/app/Application;Ljava/lang/Object;)V
Landroid/app/Service;->mActivityManager:Landroid/app/IActivityManager;
Landroid/app/Service;->mApplication:Landroid/app/Application;
@@ -1693,6 +1699,12 @@
Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider;
Landroid/content/pm/PackageParser$Service;->info:Landroid/content/pm/ServiceInfo;
Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service;
+Landroid/content/pm/PackageParser$SigningDetails$Builder;-><init>()V
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->build()Landroid/content/pm/PackageParser$SigningDetails;
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->setPastSigningCertificates([Landroid/content/pm/Signature;)Landroid/content/pm/PackageParser$SigningDetails$Builder;
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->setPastSigningCertificatesFlags([I)Landroid/content/pm/PackageParser$SigningDetails$Builder;
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->setSignatures([Landroid/content/pm/Signature;)Landroid/content/pm/PackageParser$SigningDetails$Builder;
+Landroid/content/pm/PackageParser$SigningDetails$Builder;->setSignatureSchemeVersion(I)Landroid/content/pm/PackageParser$SigningDetails$Builder;
Landroid/content/pm/PackageParser$SigningDetails;->signatures:[Landroid/content/pm/Signature;
Landroid/content/pm/PackageParser;-><init>()V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
@@ -5820,6 +5832,7 @@
Landroid/view/animation/TranslateAnimation;->mToYValue:F
Landroid/view/animation/TranslateYAnimation;-><init>(IFIF)V
Landroid/view/autofill/IAutoFillManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/view/autofill/IAutoFillManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/autofill/IAutoFillManager;
Landroid/view/Choreographer$CallbackQueue;->addCallbackLocked(JLjava/lang/Object;Ljava/lang/Object;)V
Landroid/view/Choreographer$CallbackRecord;->run(J)V
Landroid/view/Choreographer;->doFrame(JI)V
@@ -9029,6 +9042,10 @@
Lorg/w3c/dom/traversal/NodeFilter;->acceptNode(Lorg/w3c/dom/Node;)S
Lorg/w3c/dom/traversal/NodeIterator;->detach()V
Lorg/w3c/dom/traversal/NodeIterator;->nextNode()Lorg/w3c/dom/Node;
+Lorg/xml/sax/ext/Attributes2Impl;->declared:[Z
+Lorg/xml/sax/ext/Attributes2Impl;->specified:[Z
+Lorg/xml/sax/ext/Locator2Impl;->encoding:Ljava/lang/String;
+Lorg/xml/sax/ext/Locator2Impl;->version:Ljava/lang/String;
Lorg/xml/sax/helpers/AttributesImpl;->badIndex(I)V
Lorg/xml/sax/helpers/AttributesImpl;->data:[Ljava/lang/String;
Lorg/xml/sax/helpers/AttributesImpl;->ensureCapacity(I)V
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7ddf006..973ca12 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1557,6 +1557,7 @@
private final long[] mRejectTimes;
private final int mDuration;
private final int mProxyUid;
+ private final boolean mRunning;
private final String mProxyPackageName;
public OpEntry(int op, int mode, long time, long rejectTime, int duration,
@@ -1568,12 +1569,13 @@
mTimes[0] = time;
mRejectTimes[0] = rejectTime;
mDuration = duration;
+ mRunning = duration == -1;
mProxyUid = proxyUid;
mProxyPackageName = proxyPackage;
}
public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
- int proxyUid, String proxyPackage) {
+ boolean running, int proxyUid, String proxyPackage) {
mOp = op;
mMode = mode;
mTimes = new long[_NUM_UID_STATE];
@@ -1581,10 +1583,16 @@
System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE);
System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE);
mDuration = duration;
+ mRunning = running;
mProxyUid = proxyUid;
mProxyPackageName = proxyPackage;
}
+ public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+ int proxyUid, String proxyPackage) {
+ this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage);
+ }
+
public int getOp() {
return mOp;
}
@@ -1634,7 +1642,7 @@
}
public boolean isRunning() {
- return mDuration == -1;
+ return mRunning;
}
public int getDuration() {
@@ -1661,6 +1669,7 @@
dest.writeLongArray(mTimes);
dest.writeLongArray(mRejectTimes);
dest.writeInt(mDuration);
+ dest.writeBoolean(mRunning);
dest.writeInt(mProxyUid);
dest.writeString(mProxyPackageName);
}
@@ -1671,6 +1680,7 @@
mTimes = source.createLongArray();
mRejectTimes = source.createLongArray();
mDuration = source.readInt();
+ mRunning = source.readBoolean();
mProxyUid = source.readInt();
mProxyPackageName = source.readString();
}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index d445965..e7ae32d 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -255,7 +255,7 @@
/**
* @deprecated Since Android P app can no longer request restoring of its backup.
*
- * <p>Restore the calling application from backup. The data will be restored from the
+ * Restore the calling application from backup. The data will be restored from the
* current backup dataset if the application has stored data there, or from
* the dataset used during the last full device setup operation if the current
* backup dataset has no matching data. If no backup data exists for this application
@@ -282,7 +282,7 @@
/**
* @deprecated Since Android P app can no longer request restoring of its backup.
*
- * <p>Restore the calling application from backup. The data will be restored from the
+ * Restore the calling application from backup. The data will be restored from the
* current backup dataset if the application has stored data there, or from
* the dataset used during the last full device setup operation if the current
* backup dataset has no matching data. If no backup data exists for this application
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 5e75841..4c22c94 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -15,6 +15,8 @@
*/
package android.app.slice;
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+
import android.annotation.NonNull;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -29,6 +31,7 @@
import android.content.pm.ProviderInfo;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -39,6 +42,8 @@
import android.os.StrictMode.ThreadPolicy;
import android.util.ArraySet;
import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import java.util.ArrayList;
import java.util.Arrays;
@@ -472,12 +477,25 @@
}
Slice.Builder parent = new Slice.Builder(sliceUri);
Slice.Builder childAction = new Slice.Builder(parent)
+ .addIcon(Icon.createWithResource(context,
+ com.android.internal.R.drawable.ic_permission), null,
+ Collections.emptyList())
.addHints(Arrays.asList(Slice.HINT_TITLE, Slice.HINT_SHORTCUT))
.addAction(action, new Slice.Builder(parent).build(), null);
+ TypedValue tv = new TypedValue();
+ new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light)
+ .getTheme().resolveAttribute(android.R.attr.colorAccent, tv, true);
+ int deviceDefaultAccent = tv.data;
+
parent.addSubSlice(new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
+ .addIcon(Icon.createWithResource(context,
+ com.android.internal.R.drawable.ic_arrow_forward), null,
+ Collections.emptyList())
.addText(getPermissionString(context, callingPackage), null,
Collections.emptyList())
+ .addInt(deviceDefaultAccent, SUBTYPE_COLOR,
+ Collections.emptyList())
.addSubSlice(childAction.build(), null)
.build(), null);
return parent.addHints(Arrays.asList(Slice.HINT_PERMISSION_REQUEST)).build();
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 1461711..0e91a29 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1188,6 +1188,7 @@
* Determines whether the {@link Activity} is considered translucent or floating.
* @hide
*/
+ @TestApi
public static boolean isTranslucentOrFloating(TypedArray attributes) {
final boolean isTranslucent =
attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1268beb..aa0cacb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1664,7 +1664,8 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device includes at least one form of audio
- * output, such as speakers, audio jack or streaming over bluetooth
+ * output, as defined in the Android Compatibility Definition Document (CDD)
+ * <a href="https://source.android.com/compatibility/android-cdd#7_8_audio">section 7.8 Audio</a>.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 5890d98..7e7d617 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -138,6 +138,15 @@
}
/**
+ * Dump proxy debug information.
+ *
+ * @hide
+ */
+ public static void dumpProxyDebugInfo() {
+ BinderProxy.dumpProxyDebugInfo();
+ }
+
+ /**
* Check if binder transaction tracing is enabled.
*
* @hide
@@ -942,8 +951,7 @@
// about to crash.
final int totalUnclearedSize = unclearedSize();
if (totalUnclearedSize >= CRASH_AT_SIZE) {
- dumpProxyInterfaceCounts();
- dumpPerUidProxyCounts();
+ dumpProxyDebugInfo();
Runtime.getRuntime().gc();
throw new AssertionError("Binder ProxyMap has too many entries: "
+ totalSize + " (total), " + totalUnclearedSize + " (uncleared), "
@@ -1028,6 +1036,14 @@
private static ProxyMap sProxyMap = new ProxyMap();
/**
+ * @hide
+ */
+ public static void dumpProxyDebugInfo() {
+ sProxyMap.dumpProxyInterfaceCounts();
+ sProxyMap.dumpPerUidProxyCounts();
+ }
+
+ /**
* Return a BinderProxy for IBinder.
* This method is thread-hostile! The (native) caller serializes getInstance() calls using
* gProxyLock.
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index f1f6f41..d2d8f1e 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -72,12 +72,23 @@
public @interface VibrationIntensity{}
private final String mPackageName;
+ // The default vibration intensity level for haptic feedback.
+ @VibrationIntensity
+ private final int mDefaultHapticFeedbackIntensity;
+ // The default vibration intensity level for notifications.
+ @VibrationIntensity
+ private final int mDefaultNotificationVibrationIntensity;
/**
* @hide to prevent subclassing from outside of the framework
*/
public Vibrator() {
mPackageName = ActivityThread.currentPackageName();
+ final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
+ mDefaultHapticFeedbackIntensity = loadDefaultIntensity(ctx,
+ com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
+ mDefaultNotificationVibrationIntensity = loadDefaultIntensity(ctx,
+ com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
}
/**
@@ -85,6 +96,14 @@
*/
protected Vibrator(Context context) {
mPackageName = context.getOpPackageName();
+ mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
+ com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
+ mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
+ com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+ }
+
+ private int loadDefaultIntensity(Context ctx, int resId) {
+ return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM;
}
/**
@@ -92,7 +111,7 @@
* @hide
*/
public int getDefaultHapticFeedbackIntensity() {
- return VIBRATION_INTENSITY_MEDIUM;
+ return mDefaultHapticFeedbackIntensity;
}
/**
@@ -100,7 +119,7 @@
* @hide
*/
public int getDefaultNotificationVibrationIntensity() {
- return VIBRATION_INTENSITY_HIGH;
+ return mDefaultNotificationVibrationIntensity;
}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index a0cbfb6..ce334ae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -38,11 +38,10 @@
static {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
- DEFAULT_FLAGS.put("settings_about_phone_v2", "true");
DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
- DEFAULT_FLAGS.put("settings_systemui_theme", "false");
+ DEFAULT_FLAGS.put("settings_systemui_theme", "true");
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8a7d004..7944319 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5060,9 +5060,9 @@
child.assignParent(this);
} else {
child.mParent = this;
- if (child.hasUnhandledKeyListener()) {
- incrementChildUnhandledKeyListeners();
- }
+ }
+ if (child.hasUnhandledKeyListener()) {
+ incrementChildUnhandledKeyListeners();
}
final boolean childHasFocus = child.hasFocus();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 364a4a5..d34b92b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -76,7 +76,6 @@
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
@@ -1626,6 +1625,8 @@
contentInsets.top + outsets.top, contentInsets.right + outsets.right,
contentInsets.bottom + outsets.bottom);
}
+ contentInsets = ensureInsetsNonNegative(contentInsets, "content");
+ stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
mLastWindowInsets = new WindowInsets(contentInsets,
null /* windowDecorInsets */, stableInsets,
mContext.getResources().getConfiguration().isScreenRound(),
@@ -1634,6 +1635,17 @@
return mLastWindowInsets;
}
+ private Rect ensureInsetsNonNegative(Rect insets, String kind) {
+ if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
+ Log.wtf(mTag, "Negative " + kind + "Insets: " + insets + ", mFirst=" + mFirst);
+ return new Rect(Math.max(0, insets.left),
+ Math.max(0, insets.top),
+ Math.max(0, insets.right),
+ Math.max(0, insets.bottom));
+ }
+ return insets;
+ }
+
void dispatchApplyInsets(View host) {
WindowInsets insets = getWindowInsets(true /* forceConstruct */);
final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
@@ -4972,10 +4984,7 @@
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
- mUnhandledKeyManager.mDispatched = false;
-
- if (mUnhandledKeyManager.hasFocus()
- && mUnhandledKeyManager.dispatchUnique(mView, event)) {
+ if (mUnhandledKeyManager.preViewDispatch(event)) {
return FINISH_HANDLED;
}
@@ -4988,7 +4997,10 @@
return FINISH_NOT_HANDLED;
}
- if (mUnhandledKeyManager.dispatchUnique(mView, event)) {
+ // This dispatch is for windows that don't have a Window.Callback. Otherwise,
+ // the Window.Callback usually will have already called this (see
+ // DecorView.superDispatchKeyEvent) leaving this call a no-op.
+ if (mUnhandledKeyManager.dispatch(mView, event)) {
return FINISH_HANDLED;
}
@@ -7026,6 +7038,10 @@
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
+ if (q.mEvent instanceof KeyEvent) {
+ mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
+ }
+
if (stage != null) {
handleWindowFocusChanged();
stage.deliver(q);
@@ -7794,7 +7810,7 @@
* @param event
* @return {@code true} if the event was handled, {@code false} otherwise.
*/
- public boolean dispatchKeyFallbackEvent(KeyEvent event) {
+ public boolean dispatchUnhandledKeyEvent(KeyEvent event) {
return mUnhandledKeyManager.dispatch(mView, event);
}
@@ -8386,35 +8402,74 @@
}
private static class UnhandledKeyManager {
-
// This is used to ensure that unhandled events are only dispatched once. We attempt
// to dispatch more than once in order to achieve a certain order. Specifically, if we
// are in an Activity or Dialog (and have a Window.Callback), the unhandled events should
- // be dispatched after the view hierarchy, but before the Activity. However, if we aren't
+ // be dispatched after the view hierarchy, but before the Callback. However, if we aren't
// in an activity, we still want unhandled keys to be dispatched.
- boolean mDispatched = false;
+ private boolean mDispatched = true;
- SparseBooleanArray mCapturedKeys = new SparseBooleanArray();
- WeakReference<View> mCurrentReceiver = null;
+ // Keeps track of which Views have unhandled key focus for which keys. This doesn't
+ // include modifiers.
+ private final SparseArray<WeakReference<View>> mCapturedKeys = new SparseArray<>();
- private void updateCaptureState(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- mCapturedKeys.append(event.getKeyCode(), true);
+ // The current receiver. This value is transient and used between the pre-dispatch and
+ // pre-view phase to ensure that other input-stages don't interfere with tracking.
+ private WeakReference<View> mCurrentReceiver = null;
+
+ boolean dispatch(View root, KeyEvent event) {
+ if (mDispatched) {
+ return false;
}
+ View consumer;
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "UnhandledKeyEvent dispatch");
+ mDispatched = true;
+
+ consumer = root.dispatchUnhandledKeyEvent(event);
+
+ // If an unhandled listener handles one, then keep track of it so that the
+ // consuming view is first to receive its repeats and release as well.
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ int keycode = event.getKeyCode();
+ if (consumer != null && !KeyEvent.isModifierKey(keycode)) {
+ mCapturedKeys.put(keycode, new WeakReference<>(consumer));
+ }
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return consumer != null;
+ }
+
+ /**
+ * Called before the event gets dispatched to anything
+ */
+ void preDispatch(KeyEvent event) {
+ // Always clean-up 'up' events since it's possible for earlier dispatch stages to
+ // consume them without consuming the corresponding 'down' event.
+ mCurrentReceiver = null;
if (event.getAction() == KeyEvent.ACTION_UP) {
- mCapturedKeys.delete(event.getKeyCode());
+ int idx = mCapturedKeys.indexOfKey(event.getKeyCode());
+ if (idx >= 0) {
+ mCurrentReceiver = mCapturedKeys.valueAt(idx);
+ mCapturedKeys.removeAt(idx);
+ }
}
}
- boolean dispatch(View root, KeyEvent event) {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "KeyFallback dispatch");
- mDispatched = true;
-
- updateCaptureState(event);
-
+ /**
+ * Called before the event gets dispatched to the view hierarchy
+ * @return {@code true} if an unhandled handler has focus and consumed the event
+ */
+ boolean preViewDispatch(KeyEvent event) {
+ mDispatched = false;
+ if (mCurrentReceiver == null) {
+ mCurrentReceiver = mCapturedKeys.get(event.getKeyCode());
+ }
if (mCurrentReceiver != null) {
View target = mCurrentReceiver.get();
- if (mCapturedKeys.size() == 0) {
+ if (event.getAction() == KeyEvent.ACTION_UP) {
mCurrentReceiver = null;
}
if (target != null && target.isAttachedToWindow()) {
@@ -8423,24 +8478,7 @@
// consume anyways so that we don't feed uncaptured key events to other views
return true;
}
-
- View consumer = root.dispatchUnhandledKeyEvent(event);
- if (consumer != null) {
- mCurrentReceiver = new WeakReference<>(consumer);
- }
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- return consumer != null;
- }
-
- boolean hasFocus() {
- return mCurrentReceiver != null;
- }
-
- boolean dispatchUnique(View root, KeyEvent event) {
- if (mDispatched) {
- return false;
- }
- return dispatch(root, event);
+ return false;
}
}
}
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 2940079..9171959 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -156,9 +156,12 @@
if (activeServiceSupportsAssistGesture()) {
return getActiveServiceComponentName();
}
-
- Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
- .getAssistIntent(false);
+ final SearchManager searchManager =
+ (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+ if (searchManager == null) {
+ return null;
+ }
+ final Intent intent = searchManager.getAssistIntent(false);
PackageManager pm = mContext.getPackageManager();
ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY,
userId);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 571878d..4f567d2 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -76,6 +76,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ResolverActivity;
import com.android.internal.app.ResolverActivity.TargetInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -932,7 +933,7 @@
public static final int TARGET_SERVICE = 1;
public static final int TARGET_STANDARD = 2;
- private static final int MAX_SERVICE_TARGETS = 8;
+ private static final int MAX_SERVICE_TARGETS = 4;
private static final int MAX_TARGETS_PER_SERVICE = 4;
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
@@ -1189,123 +1190,20 @@
}
}
- static class RowScale {
- private static final int DURATION = 400;
-
- float mScale;
- ChooserRowAdapter mAdapter;
- private final ObjectAnimator mAnimator;
-
- public static final FloatProperty<RowScale> PROPERTY =
- new FloatProperty<RowScale>("scale") {
- @Override
- public void setValue(RowScale object, float value) {
- object.mScale = value;
- object.mAdapter.notifyDataSetChanged();
- }
-
- @Override
- public Float get(RowScale object) {
- return object.mScale;
- }
- };
-
- public RowScale(@NonNull ChooserRowAdapter adapter, float from, float to) {
- mAdapter = adapter;
- mScale = from;
- if (from == to) {
- mAnimator = null;
- return;
- }
-
- mAnimator = ObjectAnimator.ofFloat(this, PROPERTY, from, to)
- .setDuration(DURATION);
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mAdapter.onAnimationStart();
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- mAdapter.onAnimationEnd();
- }
- });
- }
-
- public RowScale setInterpolator(Interpolator interpolator) {
- if (mAnimator != null) {
- mAnimator.setInterpolator(interpolator);
- }
- return this;
- }
-
- public float get() {
- return mScale;
- }
-
- public void startAnimation() {
- if (mAnimator != null) {
- mAnimator.start();
- }
- }
-
- public void cancelAnimation() {
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- }
- }
-
class ChooserRowAdapter extends BaseAdapter {
private ChooserListAdapter mChooserListAdapter;
private final LayoutInflater mLayoutInflater;
private final int mColumnCount = 4;
- private RowScale[] mServiceTargetScale;
- private final Interpolator mInterpolator;
private int mAnimationCount = 0;
public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
mChooserListAdapter = wrappedAdapter;
mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
- mInterpolator = AnimationUtils.loadInterpolator(ChooserActivity.this,
- android.R.interpolator.decelerate_quint);
-
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
- final int rcount = getServiceTargetRowCount();
- if (mServiceTargetScale == null
- || mServiceTargetScale.length != rcount) {
- RowScale[] old = mServiceTargetScale;
- int oldRCount = old != null ? old.length : 0;
- mServiceTargetScale = new RowScale[rcount];
- if (old != null && rcount > 0) {
- System.arraycopy(old, 0, mServiceTargetScale, 0,
- Math.min(old.length, rcount));
- }
-
- for (int i = rcount; i < oldRCount; i++) {
- old[i].cancelAnimation();
- }
-
- for (int i = oldRCount; i < rcount; i++) {
- final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
- .setInterpolator(mInterpolator);
- mServiceTargetScale[i] = rs;
- }
-
- // Start the animations in a separate loop.
- // The process of starting animations will result in
- // binding views to set up initial values, and we must
- // have ALL of the new RowScale objects created above before
- // we get started.
- for (int i = oldRCount; i < rcount; i++) {
- mServiceTargetScale[i].startAnimation();
- }
- }
-
notifyDataSetChanged();
}
@@ -1313,39 +1211,10 @@
public void onInvalidated() {
super.onInvalidated();
notifyDataSetInvalidated();
- if (mServiceTargetScale != null) {
- for (RowScale rs : mServiceTargetScale) {
- rs.cancelAnimation();
- }
- }
}
});
}
- private float getRowScale(int rowPosition) {
- final int start = getCallerTargetRowCount();
- final int end = start + getServiceTargetRowCount();
- if (rowPosition >= start && rowPosition < end) {
- return mServiceTargetScale[rowPosition - start].get();
- }
- return 1.f;
- }
-
- public void onAnimationStart() {
- final boolean lock = mAnimationCount == 0;
- mAnimationCount++;
- if (lock) {
- mResolverDrawerLayout.setDismissLocked(true);
- }
- }
-
- public void onAnimationEnd() {
- mAnimationCount--;
- if (mAnimationCount == 0) {
- mResolverDrawerLayout.setDismissLocked(false);
- }
- }
-
@Override
public int getCount() {
return (int) (
@@ -1360,9 +1229,9 @@
(float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
}
+ // There can be at most one row of service targets.
public int getServiceTargetRowCount() {
- return (int) Math.ceil(
- (float) mChooserListAdapter.getServiceTargetCount() / mColumnCount);
+ return (int) mChooserListAdapter.getServiceTargetCount() == 0 ? 0 : 1;
}
@Override
@@ -1485,8 +1354,7 @@
}
final int oldHeight = holder.row.getLayoutParams().height;
- holder.row.getLayoutParams().height = Math.max(1,
- (int) (holder.measuredRowHeight * getRowScale(rowPosition)));
+ holder.row.getLayoutParams().height = Math.max(1, holder.measuredRowHeight);
if (holder.row.getLayoutParams().height != oldHeight) {
holder.row.requestLayout();
}
@@ -1728,7 +1596,7 @@
final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
- offset += (int) (height * mChooserRowAdapter.getRowScale(pos));
+ offset += (int) (height);
if (vt >= 0) {
mCachedViewType = vt;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4cc91ec..c354634 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4029,8 +4029,6 @@
public void addIsolatedUidLocked(int isolatedUid, int appUid) {
mIsolatedUids.put(isolatedUid, appUid);
- StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, appUid, isolatedUid,
- StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
final Uid u = getUidStatsLocked(appUid);
u.addIsolatedUid(isolatedUid);
}
@@ -4054,9 +4052,6 @@
*/
@GuardedBy("this")
public void removeIsolatedUidLocked(int isolatedUid) {
- StatsLog.write(
- StatsLog.ISOLATED_UID_CHANGED, mIsolatedUids.get(isolatedUid, -1),
- isolatedUid, StatsLog.ISOLATED_UID_CHANGED__EVENT__REMOVED);
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
if (idx >= 0) {
final int ownerUid = mIsolatedUids.valueAt(idx);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 9ea17d6..4697266 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -436,7 +436,7 @@
return true;
}
- return (getViewRootImpl() != null) && getViewRootImpl().dispatchKeyFallbackEvent(event);
+ return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);
}
public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index d135040..c9a9161 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -100,7 +100,6 @@
super.onFinishInflate();
mMessageContainer = findViewById(R.id.group_message_container);
mSenderName = findViewById(R.id.message_name);
- mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
mAvatarView = findViewById(R.id.message_icon);
mImageContainer = findViewById(R.id.messaging_group_icon_container);
mSendingSpinner = findViewById(R.id.messaging_group_sending_progress);
@@ -190,73 +189,66 @@
}
public void removeMessage(MessagingMessage messagingMessage) {
- ViewGroup messageParent = (ViewGroup) messagingMessage.getView().getParent();
- messageParent.removeView(messagingMessage.getView());
+ View view = messagingMessage.getView();
+ boolean wasShown = view.isShown();
+ ViewGroup messageParent = (ViewGroup) view.getParent();
+ if (messageParent == null) {
+ return;
+ }
+ messageParent.removeView(view);
Runnable recycleRunnable = () -> {
- messageParent.removeTransientView(messagingMessage.getView());
+ messageParent.removeTransientView(view);
messagingMessage.recycle();
- if (mMessageContainer.getChildCount() == 0
- && mMessageContainer.getTransientViewCount() == 0
- && mImageContainer.getChildCount() == 0) {
- ViewParent parent = getParent();
- if (parent instanceof ViewGroup) {
- ((ViewGroup) parent).removeView(MessagingGroup.this);
- }
- setAvatar(null);
- mAvatarView.setAlpha(1.0f);
- mAvatarView.setTranslationY(0.0f);
- mSenderName.setAlpha(1.0f);
- mSenderName.setTranslationY(0.0f);
- mIsolatedMessage = null;
- mMessages = null;
- sInstancePool.release(MessagingGroup.this);
- }
};
- if (isShown()) {
- messageParent.addTransientView(messagingMessage.getView(), 0);
- performRemoveAnimation(messagingMessage.getView(), recycleRunnable);
- if (mMessageContainer.getChildCount() == 0
- && mImageContainer.getChildCount() == 0) {
- removeGroupAnimated(null);
- }
+ if (wasShown && !MessagingLinearLayout.isGone(view)) {
+ messageParent.addTransientView(view, 0);
+ performRemoveAnimation(view, recycleRunnable);
} else {
recycleRunnable.run();
}
-
}
- private void removeGroupAnimated(Runnable endAction) {
- performRemoveAnimation(mAvatarView, null);
- performRemoveAnimation(mSenderName, null);
- boolean endActionTriggered = false;
- for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
- View child = mMessageContainer.getChildAt(i);
- if (child.getVisibility() == View.GONE) {
- continue;
- }
- final ViewGroup.LayoutParams lp = child.getLayoutParams();
- if (lp instanceof MessagingLinearLayout.LayoutParams
- && ((MessagingLinearLayout.LayoutParams) lp).hide
- && !((MessagingLinearLayout.LayoutParams) lp).visibleBefore) {
- continue;
- }
- Runnable childEndAction = endActionTriggered ? null : endAction;
- performRemoveAnimation(child, childEndAction);
- endActionTriggered = true;
- }
+ public void recycle() {
if (mIsolatedMessage != null) {
- performRemoveAnimation(mIsolatedMessage, !endActionTriggered ? endAction : null);
- endActionTriggered = true;
+ mImageContainer.removeView(mIsolatedMessage);
}
- if (!endActionTriggered && endAction != null) {
- endAction.run();
+ for (int i = 0; i < mMessages.size(); i++) {
+ MessagingMessage message = mMessages.get(i);
+ mMessageContainer.removeView(message.getView());
+ message.recycle();
}
+ setAvatar(null);
+ mAvatarView.setAlpha(1.0f);
+ mAvatarView.setTranslationY(0.0f);
+ mSenderName.setAlpha(1.0f);
+ mSenderName.setTranslationY(0.0f);
+ setAlpha(1.0f);
+ mIsolatedMessage = null;
+ mMessages = null;
+ mAddedMessages.clear();
+ mFirstLayout = true;
+ MessagingPropertyAnimator.recycle(this);
+ sInstancePool.release(MessagingGroup.this);
+ }
+
+ public void removeGroupAnimated(Runnable endAction) {
+ performRemoveAnimation(this, () -> {
+ setAlpha(1.0f);
+ MessagingPropertyAnimator.setToLaidOutPosition(this);
+ if (endAction != null) {
+ endAction.run();
+ }
+ });
}
public void performRemoveAnimation(View message, Runnable endAction) {
- MessagingPropertyAnimator.fadeOut(message, endAction);
- MessagingPropertyAnimator.startLocalTranslationTo(message,
- (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ performRemoveAnimation(message, -message.getHeight(), endAction);
+ }
+
+ private void performRemoveAnimation(View view, int disappearTranslation, Runnable endAction) {
+ MessagingPropertyAnimator.startLocalTranslationTo(view, disappearTranslation,
+ MessagingLayout.FAST_OUT_LINEAR_IN);
+ MessagingPropertyAnimator.fadeOut(view, endAction);
}
public CharSequence getSenderName() {
@@ -341,6 +333,11 @@
}
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
public Icon getAvatarSymbolIfMatching(CharSequence avatarName, String avatarSymbol,
int layoutColor) {
if (mAvatarName.equals(avatarName) && mAvatarSymbol.equals(avatarSymbol)
@@ -458,6 +455,7 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!mAddedMessages.isEmpty()) {
+ final boolean firstLayout = mFirstLayout;
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
@@ -466,7 +464,7 @@
continue;
}
MessagingPropertyAnimator.fadeIn(message.getView());
- if (!mFirstLayout) {
+ if (!firstLayout) {
MessagingPropertyAnimator.startLocalTranslationFrom(message.getView(),
message.getView().getHeight(),
MessagingLayout.LINEAR_OUT_SLOW_IN);
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 9db74e8..607a3a9 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -170,8 +170,6 @@
public void recycle() {
MessagingMessage.super.recycle();
- setAlpha(1.0f);
- setTranslationY(0);
setImageBitmap(null);
mDrawable = null;
sInstancePool.release(this);
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 03a734d..0fd6109 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -180,8 +180,13 @@
List<MessagingMessage> historicMessages = createMessages(newHistoricMessages,
true /* isHistoric */);
List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */);
+
+ ArrayList<MessagingGroup> oldGroups = new ArrayList<>(mGroups);
addMessagesToGroups(historicMessages, messages, showSpinner);
+ // Let's first check which groups were removed altogether and remove them in one animation
+ removeGroups(oldGroups);
+
// Let's remove the remaining messages
mMessages.forEach(REMOVE_MESSAGE);
mHistoricMessages.forEach(REMOVE_MESSAGE);
@@ -193,6 +198,31 @@
updateTitleAndNamesDisplay();
}
+ private void removeGroups(ArrayList<MessagingGroup> oldGroups) {
+ int size = oldGroups.size();
+ for (int i = 0; i < size; i++) {
+ MessagingGroup group = oldGroups.get(i);
+ if (!mGroups.contains(group)) {
+ List<MessagingMessage> messages = group.getMessages();
+ Runnable endRunnable = () -> {
+ mMessagingLinearLayout.removeTransientView(group);
+ group.recycle();
+ };
+
+ boolean wasShown = group.isShown();
+ mMessagingLinearLayout.removeView(group);
+ if (wasShown && !MessagingLinearLayout.isGone(group)) {
+ mMessagingLinearLayout.addTransientView(group, 0);
+ group.removeGroupAnimated(endRunnable);
+ } else {
+ endRunnable.run();
+ }
+ mMessages.removeAll(messages);
+ mHistoricMessages.removeAll(messages);
+ }
+ }
+ }
+
private void updateTitleAndNamesDisplay() {
ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 991e3e7..64b1f24 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -163,15 +163,6 @@
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
MessagingChild messagingChild = (MessagingChild) child;
- if (lp.hide) {
- if (shown && lp.visibleBefore) {
- messagingChild.hideAnimated();
- }
- lp.visibleBefore = false;
- continue;
- } else {
- lp.visibleBefore = true;
- }
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
@@ -182,6 +173,19 @@
} else {
childLeft = paddingLeft + lp.leftMargin;
}
+ if (lp.hide) {
+ if (shown && lp.visibleBefore) {
+ // We still want to lay out the child to have great animations
+ child.layout(childLeft, childTop, childLeft + childWidth,
+ childTop + lp.lastVisibleHeight);
+ messagingChild.hideAnimated();
+ }
+ lp.visibleBefore = false;
+ continue;
+ } else {
+ lp.visibleBefore = true;
+ lp.lastVisibleHeight = childHeight;
+ }
if (!first) {
childTop += mSpacing;
@@ -228,6 +232,18 @@
return copy;
}
+ public static boolean isGone(View view) {
+ if (view.getVisibility() == View.GONE) {
+ return true;
+ }
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Sets how many lines should be displayed at most
*/
@@ -263,6 +279,7 @@
public boolean hide = false;
public boolean visibleBefore = false;
+ public int lastVisibleHeight;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index ffcb503..74d0aae 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -124,8 +124,7 @@
@Override
default void hideAnimated() {
setIsHidingAnimated(true);
- getGroup().performRemoveAnimation(getState().getHostView(),
- () -> setIsHidingAnimated(false));
+ getGroup().performRemoveAnimation(getView(), () -> setIsHidingAnimated(false));
}
default boolean hasOverlappingRendering() {
@@ -133,7 +132,7 @@
}
default void recycle() {
- getState().reset();
+ getState().recycle();
}
default View getView() {
diff --git a/core/java/com/android/internal/widget/MessagingMessageState.java b/core/java/com/android/internal/widget/MessagingMessageState.java
index ac62472..1ba2b51 100644
--- a/core/java/com/android/internal/widget/MessagingMessageState.java
+++ b/core/java/com/android/internal/widget/MessagingMessageState.java
@@ -72,7 +72,10 @@
return mHostView;
}
- public void reset() {
+ public void recycle() {
+ mHostView.setAlpha(1.0f);
+ mHostView.setTranslationY(0);
+ MessagingPropertyAnimator.recycle(mHostView);
mIsHidingAnimated = false;
mIsHistoric = false;
mGroup = null;
diff --git a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
index 7c3ab7f..7703cb0 100644
--- a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
+++ b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
@@ -31,111 +31,125 @@
* A listener that automatically starts animations when the layout bounds change.
*/
public class MessagingPropertyAnimator implements View.OnLayoutChangeListener {
- static final long APPEAR_ANIMATION_LENGTH = 210;
+ private static final long APPEAR_ANIMATION_LENGTH = 210;
private static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- private static final int TAG_LOCAL_TRANSLATION_ANIMATOR = R.id.tag_local_translation_y_animator;
- private static final int TAG_LOCAL_TRANSLATION_Y = R.id.tag_local_translation_y;
+ private static final int TAG_TOP_ANIMATOR = R.id.tag_top_animator;
+ private static final int TAG_TOP = R.id.tag_top_override;
private static final int TAG_LAYOUT_TOP = R.id.tag_layout_top;
+ private static final int TAG_FIRST_LAYOUT = R.id.tag_is_first_layout;
private static final int TAG_ALPHA_ANIMATOR = R.id.tag_alpha_animator;
private static final ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS =
view -> view.getId() == com.android.internal.R.id.notification_messaging;
- private static final IntProperty<View> LOCAL_TRANSLATION_Y =
- new IntProperty<View>("localTranslationY") {
+ private static final IntProperty<View> TOP =
+ new IntProperty<View>("top") {
@Override
public void setValue(View object, int value) {
- setLocalTranslationY(object, value);
+ setTop(object, value);
}
@Override
public Integer get(View object) {
- return getLocalTranslationY(object);
+ return getTop(object);
}
};
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- int oldHeight = oldBottom - oldTop;
- Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
- if (layoutTop != null) {
- oldTop = layoutTop;
- }
- int topChange = oldTop - top;
- if (oldHeight == 0 || topChange == 0 || !v.isShown() || isGone(v)) {
- // First layout
+ setLayoutTop(v, top);
+ if (isFirstLayout(v)) {
+ setFirstLayout(v, false /* first */);
+ setTop(v, top);
return;
}
- if (layoutTop != null) {
- v.setTagInternal(TAG_LAYOUT_TOP, top);
- }
- int newHeight = bottom - top;
- int heightDifference = oldHeight - newHeight;
- // Only add the difference if the height changes and it's getting smaller
- heightDifference = Math.max(heightDifference, 0);
- startLocalTranslationFrom(v, topChange + heightDifference + getLocalTranslationY(v));
+ startTopAnimation(v, getTop(v), top, MessagingLayout.FAST_OUT_SLOW_IN);
}
- private boolean isGone(View view) {
- if (view.getVisibility() == View.GONE) {
- return true;
- }
- final ViewGroup.LayoutParams lp = view.getLayoutParams();
- if (lp instanceof MessagingLinearLayout.LayoutParams
- && ((MessagingLinearLayout.LayoutParams) lp).hide) {
- return true;
- }
- return false;
- }
-
- public static void startLocalTranslationFrom(View v, int startTranslation) {
- startLocalTranslationFrom(v, startTranslation, MessagingLayout.FAST_OUT_SLOW_IN);
- }
-
- public static void startLocalTranslationFrom(View v, int startTranslation,
- Interpolator interpolator) {
- startLocalTranslation(v, startTranslation, 0, interpolator);
- }
-
- public static void startLocalTranslationTo(View v, int endTranslation,
- Interpolator interpolator) {
- startLocalTranslation(v, getLocalTranslationY(v), endTranslation, interpolator);
- }
-
- public static int getLocalTranslationY(View v) {
- Integer tag = (Integer) v.getTag(TAG_LOCAL_TRANSLATION_Y);
+ private static boolean isFirstLayout(View view) {
+ Boolean tag = (Boolean) view.getTag(TAG_FIRST_LAYOUT);
if (tag == null) {
- return 0;
+ return true;
}
return tag;
}
- private static void setLocalTranslationY(View v, int value) {
- v.setTagInternal(TAG_LOCAL_TRANSLATION_Y, value);
+ public static void recycle(View view) {
+ setFirstLayout(view, true /* first */);
+ }
+
+ private static void setFirstLayout(View view, boolean first) {
+ view.setTagInternal(TAG_FIRST_LAYOUT, first);
+ }
+
+ private static void setLayoutTop(View view, int top) {
+ view.setTagInternal(TAG_LAYOUT_TOP, top);
+ }
+
+ public static int getLayoutTop(View view) {
+ Integer tag = (Integer) view.getTag(TAG_LAYOUT_TOP);
+ if (tag == null) {
+ return getTop(view);
+ }
+ return tag;
+ }
+
+ /**
+ * Start a translation animation from a start offset to the laid out location
+ * @param view The view to animate
+ * @param startTranslation The starting translation to start from.
+ * @param interpolator The interpolator to use.
+ */
+ public static void startLocalTranslationFrom(View view, int startTranslation,
+ Interpolator interpolator) {
+ startTopAnimation(view, getTop(view) + startTranslation, getLayoutTop(view), interpolator);
+ }
+
+ /**
+ * Start a translation animation from a start offset to the laid out location
+ * @param view The view to animate
+ * @param endTranslation The end translation to go to.
+ * @param interpolator The interpolator to use.
+ */
+ public static void startLocalTranslationTo(View view, int endTranslation,
+ Interpolator interpolator) {
+ int top = getTop(view);
+ startTopAnimation(view, top, top + endTranslation, interpolator);
+ }
+
+ public static int getTop(View v) {
+ Integer tag = (Integer) v.getTag(TAG_TOP);
+ if (tag == null) {
+ return v.getTop();
+ }
+ return tag;
+ }
+
+ private static void setTop(View v, int value) {
+ v.setTagInternal(TAG_TOP, value);
updateTopAndBottom(v);
}
private static void updateTopAndBottom(View v) {
- int layoutTop = (int) v.getTag(TAG_LAYOUT_TOP);
- int localTranslation = getLocalTranslationY(v);
+ int top = getTop(v);
int height = v.getHeight();
- v.setTop(layoutTop + localTranslation);
- v.setBottom(layoutTop + height + localTranslation);
+ v.setTop(top);
+ v.setBottom(height + top);
}
- private static void startLocalTranslation(final View v, int start, int end,
+ private static void startTopAnimation(final View v, int start, int end,
Interpolator interpolator) {
- ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR);
+ ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_TOP_ANIMATOR);
if (existing != null) {
existing.cancel();
}
- ObjectAnimator animator = ObjectAnimator.ofInt(v, LOCAL_TRANSLATION_Y, start, end);
- Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
- if (layoutTop == null) {
- layoutTop = v.getTop();
- v.setTagInternal(TAG_LAYOUT_TOP, layoutTop);
+ if (!v.isShown() || start == end
+ || (MessagingLinearLayout.isGone(v) && !isHidingAnimated(v))) {
+ setTop(v, end);
+ return;
}
- setLocalTranslationY(v, start);
+ ObjectAnimator animator = ObjectAnimator.ofInt(v, TOP, start, end);
+ setTop(v, start);
animator.setInterpolator(interpolator);
animator.setDuration(APPEAR_ANIMATION_LENGTH);
animator.addListener(new AnimatorListenerAdapter() {
@@ -143,12 +157,8 @@
@Override
public void onAnimationEnd(Animator animation) {
- v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, null);
+ v.setTagInternal(TAG_TOP_ANIMATOR, null);
setClippingDeactivated(v, false);
- if (!mCancelled) {
- setLocalTranslationY(v, 0);
- v.setTagInternal(TAG_LAYOUT_TOP, null);
- }
}
@Override
@@ -157,10 +167,17 @@
}
});
setClippingDeactivated(v, true);
- v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, animator);
+ v.setTagInternal(TAG_TOP_ANIMATOR, animator);
animator.start();
}
+ private static boolean isHidingAnimated(View v) {
+ if (v instanceof MessagingLinearLayout.MessagingChild) {
+ return ((MessagingLinearLayout.MessagingChild) v).isHidingAnimated();
+ }
+ return false;
+ }
+
public static void fadeIn(final View v) {
ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_ALPHA_ANIMATOR);
if (existing != null) {
@@ -199,6 +216,13 @@
if (existing != null) {
existing.cancel();
}
+ if (!view.isShown() || (MessagingLinearLayout.isGone(view) && !isHidingAnimated(view))) {
+ view.setAlpha(0.0f);
+ if (endAction != null) {
+ endAction.run();
+ }
+ return;
+ }
ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA,
view.getAlpha(), 0.0f);
animator.setInterpolator(ALPHA_OUT);
@@ -224,10 +248,14 @@
}
public static boolean isAnimatingTranslation(View v) {
- return v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR) != null;
+ return v.getTag(TAG_TOP_ANIMATOR) != null;
}
public static boolean isAnimatingAlpha(View v) {
return v.getTag(TAG_ALPHA_ANIMATOR) != null;
}
+
+ public static void setToLaidOutPosition(View view) {
+ setTop(view, getLayoutTop(view));
+ }
}
diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java
index 219116e..4081a86 100644
--- a/core/java/com/android/internal/widget/MessagingTextMessage.java
+++ b/core/java/com/android/internal/widget/MessagingTextMessage.java
@@ -92,8 +92,6 @@
public void recycle() {
MessagingMessage.super.recycle();
- setAlpha(1.0f);
- setTranslationY(0);
sInstancePool.release(this);
}
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 4f318ff3..e5aea97 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -62,7 +62,7 @@
}
bool valid() {
- return mBitmap;
+ return mBitmap != nullptr;
}
Bitmap& bitmap() {
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c7ad2a4..fb571df 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -44,9 +44,9 @@
struct NativeFamilyBuilder {
NativeFamilyBuilder(uint32_t langId, int variant)
- : langId(langId), variant(static_cast<minikin::FontFamily::Variant>(variant)) {}
+ : langId(langId), variant(static_cast<minikin::FamilyVariant>(variant)) {}
uint32_t langId;
- minikin::FontFamily::Variant variant;
+ minikin::FamilyVariant variant;
std::vector<minikin::Font> fonts;
std::vector<minikin::FontVariation> axes;
};
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e9c2e7a..d391de7 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -44,6 +44,7 @@
#include <minikin/GraphemeBreak.h>
#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
+#include <minikin/MinikinPaint.h>
#include <unicode/utf16.h>
#include <cassert>
@@ -594,7 +595,7 @@
// restore the original settings.
paint->setTextSkewX(saveSkewX);
paint->setFakeBoldText(savefakeBold);
- if (paint->getFamilyVariant() == minikin::FontFamily::Variant::ELEGANT) {
+ if (paint->getFamilyVariant() == minikin::FamilyVariant::ELEGANT) {
SkScalar size = paint->getTextSize();
metrics->fTop = -size * kElegantTop / 2048;
metrics->fBottom = -size * kElegantBottom / 2048;
@@ -893,13 +894,13 @@
static jboolean isElegantTextHeight(jlong paintHandle) {
Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- return obj->getFamilyVariant() == minikin::FontFamily::Variant::ELEGANT;
+ return obj->getFamilyVariant() == minikin::FamilyVariant::ELEGANT;
}
static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
Paint* obj = reinterpret_cast<Paint*>(paintHandle);
obj->setFamilyVariant(
- aa ? minikin::FontFamily::Variant::ELEGANT : minikin::FontFamily::Variant::DEFAULT);
+ aa ? minikin::FamilyVariant::ELEGANT : minikin::FamilyVariant::DEFAULT);
}
static jfloat getTextSize(jlong paintHandle) {
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 418e15b..9d24588 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -117,6 +117,7 @@
optional bool visible = 4;
optional bool front_of_task = 5;
optional int32 proc_id = 6;
+ optional bool translucent = 7;
}
message KeyguardControllerProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ee54ee1..1b41f99 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -850,7 +850,7 @@
<!-- Used for permissions that are associated telephony features. -->
<permission-group android:name="android.permission-group.CALL_LOG"
- android:icon="@drawable/perm_group_phone_calls"
+ android:icon="@drawable/perm_group_call_log"
android:label="@string/permgrouplab_calllog"
android:description="@string/permgroupdesc_calllog"
android:request="@string/permgrouprequest_calllog"
diff --git a/core/res/res/drawable/ic_arrow_forward.xml b/core/res/res/drawable/ic_arrow_forward.xml
new file mode 100644
index 0000000..f108570
--- /dev/null
+++ b/core/res/res/drawable/ic_arrow_forward.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.0,4.0l-1.41,1.41L16.17,11.0L4.0,11.0l0.0,2.0l12.17,0.0l-5.58,5.59L12.0,20.0l8.0,-8.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_permission.xml b/core/res/res/drawable/ic_permission.xml
new file mode 100644
index 0000000..0052350
--- /dev/null
+++ b/core/res/res/drawable/ic_permission.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="16.0"
+ android:viewportHeight="16.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="
+ M9.0,12l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0z
+ m0.0,-4.0l-2.0,0.0l0.0,-4.0l2.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_call_log.xml b/core/res/res/drawable/perm_group_call_log.xml
new file mode 100644
index 0000000..0dfdbee
--- /dev/null
+++ b/core/res/res/drawable/perm_group_call_log.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M16.01,14.48l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.82c-0.09,-0.47 -0.5,-0.8 -0.98,-0.8L4,3.01c-0.56,0 -1.03,0.47 -1,1.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.26,-0.65C16.58,14.14 16.24,14.24 16.01,14.48z"/>
+ <path
+ android:fillColor="#000000"
+ android:pathData="M12,8h10V6H12V8zM12,4h10V2H12V4zM22,10H12v2h10V10z"/>
+</vector>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b0ecb3e..c856ed8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1108,6 +1108,15 @@
<string-array translatable="false" name="config_ringtoneEffectUris">
</string-array>
+ <!-- The default intensity level for haptic feedback. See
+ Settings.System.HAPTIC_FEEDBACK_INTENSITY more details on the constant values and
+ meanings. -->
+ <integer name="config_defaultHapticFeedbackIntensity">2</integer>
+ <!-- The default intensity level for notification vibrations. See
+ Settings.System.NOTIFICATION_VIBRATION_INTENSITY more details on the constant values and
+ meanings. -->
+ <integer name="config_defaultNotificationVibrationIntensity">2</integer>
+
<bool name="config_use_strict_phone_number_comparation">false</bool>
<!-- Display low battery warning when battery level dips to this value.
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 47d04ed..bf7e068 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -140,15 +140,18 @@
<!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. -->
<item type="id" name="accessibilityActionMoveWindow" />
- <!-- A tag used to save an animator in local y translation -->
- <item type="id" name="tag_local_translation_y_animator" />
+ <!-- A tag used to save an animator in top -->
+ <item type="id" name="tag_top_animator" />
- <!-- A tag used to save the local translation y -->
- <item type="id" name="tag_local_translation_y" />
+ <!-- A tag used to save the current top override -->
+ <item type="id" name="tag_top_override" />
<!-- A tag used to save the original top of a view -->
<item type="id" name="tag_layout_top" />
+ <!-- A tag used to save whether a view was laid out before -->
+ <item type="id" name="tag_is_first_layout" />
+
<!-- A tag used to save an animator in alpha -->
<item type="id" name="tag_alpha_animator" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 42aad6a..833228b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3260,9 +3260,10 @@
<java-symbol type="id" name="message_name" />
<java-symbol type="id" name="message_icon" />
<java-symbol type="id" name="group_message_container" />
- <java-symbol type="id" name="tag_local_translation_y_animator" />
- <java-symbol type="id" name="tag_local_translation_y" />
+ <java-symbol type="id" name="tag_top_animator" />
+ <java-symbol type="id" name="tag_top_override" />
<java-symbol type="id" name="tag_layout_top" />
+ <java-symbol type="id" name="tag_is_first_layout" />
<java-symbol type="id" name="tag_alpha_animator" />
<java-symbol type="id" name="clip_children_set_tag" />
<java-symbol type="id" name="clip_to_padding_tag" />
@@ -3389,4 +3390,9 @@
<java-symbol type="attr" name="opticalInsetBottom" />
<java-symbol type="drawable" name="ic_lock_lockdown" />
+ <java-symbol type="drawable" name="ic_arrow_forward" />
+ <java-symbol type="drawable" name="ic_permission" />
+
+ <java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
+ <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
</resources>
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
new file mode 100644
index 0000000..c8e46fc
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 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 android.view;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewRootImplTest {
+
+ private Context mContext;
+ private ViewRootImplAccessor mViewRootImpl;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mViewRootImpl = new ViewRootImplAccessor(
+ new ViewRootImpl(mContext, mContext.getDisplay()));
+ });
+ }
+
+ @Test
+ public void negativeInsets_areSetToZero() throws Exception {
+ mViewRootImpl.getAttachInfo().getContentInsets().set(-10, -20, -30 , -40);
+ mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
+ final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
+
+ assertThat(insets.getSystemWindowInsets(), equalTo(new Rect()));
+ assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+ insets.getStableInsetRight(), insets.getStableInsetBottom()), equalTo(new Rect()));
+ }
+
+ @Test
+ public void negativeInsets_areSetToZero_positiveAreLeftAsIs() throws Exception {
+ mViewRootImpl.getAttachInfo().getContentInsets().set(-10, 20, -30 , 40);
+ mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
+ final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
+
+ assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(0, 20, 0, 40)));
+ assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+ insets.getStableInsetRight(), insets.getStableInsetBottom()),
+ equalTo(new Rect(10, 0, 30, 0)));
+ }
+
+ @Test
+ public void positiveInsets_areLeftAsIs() throws Exception {
+ mViewRootImpl.getAttachInfo().getContentInsets().set(10, 20, 30 , 40);
+ mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
+ final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
+
+ assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(10, 20, 30, 40)));
+ assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+ insets.getStableInsetRight(), insets.getStableInsetBottom()),
+ equalTo(new Rect(10, 20, 30, 40)));
+ }
+
+ private static class ViewRootImplAccessor {
+
+ private final ViewRootImpl mViewRootImpl;
+
+ ViewRootImplAccessor(ViewRootImpl viewRootImpl) {
+ mViewRootImpl = viewRootImpl;
+ }
+
+ public ViewRootImpl get() {
+ return mViewRootImpl;
+ }
+
+ AttachInfoAccessor getAttachInfo() throws Exception {
+ return new AttachInfoAccessor(
+ getField(mViewRootImpl, ViewRootImpl.class.getDeclaredField("mAttachInfo")));
+ }
+
+ WindowInsets getWindowInsets(boolean forceConstruct) throws Exception {
+ return (WindowInsets) invokeMethod(mViewRootImpl,
+ ViewRootImpl.class.getDeclaredMethod("getWindowInsets", boolean.class),
+ forceConstruct);
+ }
+
+ class AttachInfoAccessor {
+
+ private final Class<?> mClass;
+ private final Object mAttachInfo;
+
+ AttachInfoAccessor(Object attachInfo) throws Exception {
+ mAttachInfo = attachInfo;
+ mClass = ViewRootImpl.class.getClassLoader().loadClass(
+ "android.view.View$AttachInfo");
+ }
+
+ Rect getContentInsets() throws Exception {
+ return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mContentInsets"));
+ }
+
+ Rect getStableInsets() throws Exception {
+ return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mStableInsets"));
+ }
+ }
+
+ private static Object getField(Object o, Field field) throws Exception {
+ field.setAccessible(true);
+ return field.get(o);
+ }
+
+ private static Object invokeMethod(Object o, Method method, Object... args)
+ throws Exception {
+ method.setAccessible(true);
+ return method.invoke(o, args);
+ }
+ }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index a6cbd49..df84a4c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -186,8 +186,6 @@
file="/system/framework/android.test.mock.jar" />
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
- <library name="javax.obex"
- file="/system/framework/javax.obex.jar" />
<!-- These are the standard packages that are white-listed to always have internet
access while in power save mode, even if they aren't in the foreground. -->
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a52263c..0022c93 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -22,6 +22,11 @@
#include <SkTypeface.h>
#include <log/log.h>
+#include <minikin/Font.h>
+#include <minikin/MinikinExtent.h>
+#include <minikin/MinikinPaint.h>
+#include <minikin/MinikinRect.h>
+
namespace android {
MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 002f759..31d3c0d 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -25,6 +25,7 @@
#include <string>
#include <minikin/FontFamily.h>
+#include <minikin/FamilyVariant.h>
namespace android {
@@ -73,9 +74,9 @@
uint32_t getMinikinLocaleListId() const { return mMinikinLocaleListId; }
- void setFamilyVariant(minikin::FontFamily::Variant variant) { mFamilyVariant = variant; }
+ void setFamilyVariant(minikin::FamilyVariant variant) { mFamilyVariant = variant; }
- minikin::FontFamily::Variant getFamilyVariant() const { return mFamilyVariant; }
+ minikin::FamilyVariant getFamilyVariant() const { return mFamilyVariant; }
void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; }
@@ -90,7 +91,7 @@
float mWordSpacing = 0;
std::string mFontFeatureSettings;
uint32_t mMinikinLocaleListId;
- minikin::FontFamily::Variant mFamilyVariant;
+ minikin::FamilyVariant mFamilyVariant;
uint32_t mHyphenEdit = 0;
// The native Typeface object has the same lifetime of the Java Typeface
// object. The Java Paint object holds a strong reference to the Java Typeface
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index ae9c475..29cc890 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -24,7 +24,7 @@
, mWordSpacing(0)
, mFontFeatureSettings()
, mMinikinLocaleListId(0)
- , mFamilyVariant(minikin::FontFamily::Variant::DEFAULT) {}
+ , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {}
Paint::Paint(const Paint& paint)
: SkPaint(paint)
@@ -42,7 +42,7 @@
, mWordSpacing(0)
, mFontFeatureSettings()
, mMinikinLocaleListId(0)
- , mFamilyVariant(minikin::FontFamily::Variant::DEFAULT) {}
+ , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {}
Paint::~Paint() {}
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 00ba7130..14d31b2 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -114,7 +114,7 @@
}
}
- return layerImage;
+ return layerImage != nullptr;
}
}; // namespace skiapipeline
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 02bf4e3..2207a2a 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2545,6 +2545,10 @@
pattern = newPattern;
}
+ private void setPattern(int blocksToEncrypt, int blocksToSkip) {
+ pattern = new Pattern(blocksToEncrypt, blocksToSkip);
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index a855526..15957c6 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -52,6 +52,7 @@
jfieldID context;
jmethodID cryptoInfoSetID;
+ jmethodID cryptoInfoSetPatternID;
};
static fields_t gFields;
@@ -654,6 +655,16 @@
ivObj,
mode);
+ int32_t encryptedByteBlock = 0, skipByteBlock = 0;
+ meta->findInt32(kKeyEncryptedByteBlock, &encryptedByteBlock);
+ meta->findInt32(kKeySkipByteBlock, &skipByteBlock);
+
+ env->CallVoidMethod(
+ cryptoInfoObj,
+ gFields.cryptoInfoSetPatternID,
+ encryptedByteBlock,
+ skipByteBlock);
+
return JNI_TRUE;
}
@@ -669,6 +680,9 @@
gFields.cryptoInfoSetID =
env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
+
+ gFields.cryptoInfoSetPatternID =
+ env->GetMethodID(clazz, "setPattern", "(II)V");
}
static void android_media_MediaExtractor_native_setup(
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 3185ea2..e50a375 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -24,7 +24,7 @@
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
- <application>
+ <application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner" />
<activity android:label="@string/app_name"
android:name="MediaFrameworkTest"
diff --git a/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml b/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml
new file mode 100644
index 0000000..c15c09c
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <base-config cleartextTrafficPermitted="true"/>
+</network-security-config>
diff --git a/obex/Android.bp b/obex/Android.bp
new file mode 100644
index 0000000..6558eb3
--- /dev/null
+++ b/obex/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2018 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.
+//
+
+java_sdk_library {
+ name: "javax.obex",
+ srcs: ["javax/**/*.java"],
+ api_packages: ["javax.obex"],
+}
diff --git a/obex/Android.mk b/obex/Android.mk
deleted file mode 100644
index e7c1fd3..0000000
--- a/obex/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obex
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obexstatic
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/obex/CleanSpec.mk b/obex/CleanSpec.mk
new file mode 100644
index 0000000..c104234
--- /dev/null
+++ b/obex/CleanSpec.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2018 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.
+#
+
+# runtime lib is renamed from javax.obex.jar to javax.obex.impl.jar
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/javax.obex.jar)
diff --git a/obex/api/current.txt b/obex/api/current.txt
new file mode 100644
index 0000000..1cd562f
--- /dev/null
+++ b/obex/api/current.txt
@@ -0,0 +1,12 @@
+package javax.obex {
+
+ public class ObexPacket {
+ method public static javax.obex.ObexPacket read(java.io.InputStream) throws java.io.IOException;
+ method public static javax.obex.ObexPacket read(int, java.io.InputStream) throws java.io.IOException;
+ field public int mHeaderId;
+ field public int mLength;
+ field public byte[] mPayload;
+ }
+
+}
+
diff --git a/obex/api/removed.txt b/obex/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/removed.txt
diff --git a/obex/api/system-current.txt b/obex/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-current.txt
diff --git a/obex/api/system-removed.txt b/obex/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-removed.txt
diff --git a/obex/api/test-current.txt b/obex/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-current.txt
diff --git a/obex/api/test-removed.txt b/obex/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-removed.txt
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 6186a78..e645adc 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -66,10 +66,11 @@
LOCAL_MULTILIB := both
LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
# out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
@@ -111,10 +112,11 @@
LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
# frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index ee24bd0..8a1c4ef 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -16,17 +16,22 @@
package com.android.settingslib.fuelgauge;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
-import androidx.annotation.VisibleForTesting;
+import android.telecom.DefaultDialerManager;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.ArrayUtils;
+import androidx.annotation.VisibleForTesting;
+
/**
* Handles getting/changing the whitelist for the exceptions to battery saving features.
*/
@@ -38,19 +43,20 @@
private static PowerWhitelistBackend sInstance;
+ private final Context mAppContext;
private final IDeviceIdleController mDeviceIdleService;
private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>();
- public PowerWhitelistBackend() {
- mDeviceIdleService = IDeviceIdleController.Stub.asInterface(
- ServiceManager.getService(DEVICE_IDLE_SERVICE));
- refreshList();
+ public PowerWhitelistBackend(Context context) {
+ this(context, IDeviceIdleController.Stub.asInterface(
+ ServiceManager.getService(DEVICE_IDLE_SERVICE)));
}
@VisibleForTesting
- PowerWhitelistBackend(IDeviceIdleController deviceIdleService) {
+ PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) {
+ mAppContext = context.getApplicationContext();
mDeviceIdleService = deviceIdleService;
refreshList();
}
@@ -64,7 +70,27 @@
}
public boolean isWhitelisted(String pkg) {
- return mWhitelistedApps.contains(pkg);
+ if (mWhitelistedApps.contains(pkg)) {
+ return true;
+ }
+
+ // Additionally, check if pkg is default dialer/sms. They are considered essential apps and
+ // should be automatically whitelisted (otherwise user may be able to set restriction on
+ // them, leading to bad device behavior.)
+ if (!mAppContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return false;
+ }
+ final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext,
+ true /* updateIfNeeded */);
+ if (defaultSms != null && TextUtils.equals(pkg, defaultSms.getPackageName())) {
+ return true;
+ }
+
+ final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mAppContext);
+ if (TextUtils.equals(pkg, defaultDialer)) {
+ return true;
+ }
+ return false;
}
public boolean isWhitelisted(String[] pkgs) {
@@ -120,16 +146,19 @@
mSysWhitelistedApps.clear();
mSysWhitelistedAppsExceptIdle.clear();
mWhitelistedApps.clear();
+ if (mDeviceIdleService == null) {
+ return;
+ }
try {
- String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
+ final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
for (String app : whitelistedApps) {
mWhitelistedApps.add(app);
}
- String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
+ final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
for (String app : sysWhitelistedApps) {
mSysWhitelistedApps.add(app);
}
- String[] sysWhitelistedAppsExceptIdle =
+ final String[] sysWhitelistedAppsExceptIdle =
mDeviceIdleService.getSystemPowerWhitelistExceptIdle();
for (String app : sysWhitelistedAppsExceptIdle) {
mSysWhitelistedAppsExceptIdle.add(app);
@@ -139,9 +168,9 @@
}
}
- public static PowerWhitelistBackend getInstance() {
+ public static PowerWhitelistBackend getInstance(Context context) {
if (sInstance == null) {
- sInstance = new PowerWhitelistBackend();
+ sInstance = new PowerWhitelistBackend(context);
}
return sInstance;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index 0af2c05..a23eebc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -23,35 +23,52 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.IDeviceIdleController;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
+import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowPackageManager;
@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class})
public class PowerWhitelistBackendTest {
private static final String PACKAGE_ONE = "com.example.packageone";
private static final String PACKAGE_TWO = "com.example.packagetwo";
- private PowerWhitelistBackend mPowerWhitelistBackend;
@Mock
private IDeviceIdleController mDeviceIdleService;
+ private PowerWhitelistBackend mPowerWhitelistBackend;
+ private ShadowPackageManager mPackageManager;
+ private Context mContext;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString());
doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
- mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService);
+ mPackageManager = Shadow.extract(mContext.getPackageManager());
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
+
+ mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
}
@Test
@@ -61,8 +78,8 @@
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
mPowerWhitelistBackend.addApp(PACKAGE_TWO);
@@ -70,15 +87,15 @@
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(
- new String[]{PACKAGE_ONE, PACKAGE_TWO})).isTrue();
+ new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue();
mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
@@ -86,7 +103,23 @@
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
assertThat(mPowerWhitelistBackend.isWhitelisted(
- new String[]{PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+ new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+ }
+
+ @Test
+ public void isWhitelisted_shouldWhitelistDefaultSms() {
+ final String testSms = "com.android.test.defaultsms";
+ ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
+
+ assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue();
+ }
+
+ @Test
+ public void isWhitelisted_shouldWhitelistDefaultDialer() {
+ final String testDialer = "com.android.test.defaultdialer";
+ ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
+
+ assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue();
}
@Test
@@ -101,7 +134,7 @@
@Test
public void testIsSystemWhitelistedExceptIdle_onePackage() throws Exception {
- doReturn(new String[]{PACKAGE_TWO}).when(
+ doReturn(new String[] {PACKAGE_TWO}).when(
mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
mPowerWhitelistBackend.refreshList();
@@ -111,7 +144,7 @@
@Test
public void testIsSystemWhitelistedExceptIdle_packageArray() throws Exception {
- doReturn(new String[]{PACKAGE_TWO}).when(
+ doReturn(new String[] {PACKAGE_TWO}).when(
mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
mPowerWhitelistBackend.refreshList();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
new file mode 100644
index 0000000..f4afdb1
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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.settingslib.testutils.shadow;
+
+import android.content.Context;
+import android.telecom.DefaultDialerManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(DefaultDialerManager.class)
+public class ShadowDefaultDialerManager {
+
+ private static String sDefaultDailer;
+
+ @Resetter
+ public void reset() {
+ sDefaultDailer = null;
+ }
+
+ @Implementation
+ public static String getDefaultDialerApplication(Context context) {
+ return sDefaultDailer;
+ }
+
+ public static void setDefaultDialerApplication(String dialer) {
+ sDefaultDailer = dialer;
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
new file mode 100644
index 0000000..dd7b007
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.settingslib.testutils.shadow;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.internal.telephony.SmsApplication;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(SmsApplication.class)
+public class ShadowSmsApplication {
+
+ private static ComponentName sDefaultSmsApplication;
+
+ @Resetter
+ public void reset() {
+ sDefaultSmsApplication = null;
+ }
+
+ @Implementation
+ public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
+ return sDefaultSmsApplication;
+ }
+
+ public static void setDefaultSmsApplication(ComponentName cn) {
+ sDefaultSmsApplication = cn;
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 28e8db9..e1a602b 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -214,4 +214,7 @@
<!-- Default for Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS -->
<string name="def_backup_agent_timeout_parameters"></string>
+
+ <!-- Default for Settings.System.VIBRATE_WHEN_RINGING -->
+ <bool name="def_vibrate_when_ringing">false</bool>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index fbe52d1..960d305 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 168;
+ private static final int SETTINGS_VERSION = 169;
private final int mUserId;
@@ -3805,6 +3805,21 @@
currentVersion = 168;
}
+ if (currentVersion == 168) {
+ // Version 168: by default, vibrate for phone calls
+ final SettingsState systemSettings = getSystemSettingsLocked(userId);
+ final Setting currentSetting = systemSettings.getSettingLocked(
+ Settings.System.VIBRATE_WHEN_RINGING);
+ if (currentSetting.isNull()) {
+ systemSettings.insertSettingLocked(
+ Settings.System.VIBRATE_WHEN_RINGING,
+ getContext().getResources().getBoolean(
+ R.bool.def_vibrate_when_ringing) ? "1" : "0",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 169;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a92df74..8eee0d5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -211,6 +211,8 @@
<!-- Permission necessary to change car audio volume through CarAudioManager -->
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
+ <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..0899d35
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..2266449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..3328add
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..ed651da
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..06e1202
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index c70e829..e67bb60 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -93,7 +93,7 @@
android:layout_gravity="center"
android:contentDescription="@string/accessibility_volume_settings"
android:background="@drawable/ripple_drawable_20dp"
- android:tint="?android:attr/textColorHint"
+ android:tint="?android:attr/textColorSecondary"
android:soundEffectsEnabled="false" />
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d8607cc..975055c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -125,9 +125,6 @@
<color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
<color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
- <color name="volume_settings_icon_color">#7fffffff</color>
- <color name="volume_slider_inactive">@*android:color/quaternary_device_default_settings</color>
-
<color name="docked_divider_background">#ff000000</color>
<color name="docked_divider_handle">#ffffff</color>
<drawable name="forced_resizable_background">#59000000</drawable>
@@ -141,7 +138,7 @@
<color name="remote_input_accent">#eeeeee</color>
<color name="quick_step_track_background_dark">#61000000</color>
- <color name="quick_step_track_background_light">#4DFFFFFF</color>
+ <color name="quick_step_track_background_light">#33FFFFFF</color>
<!-- Keyboard shortcuts colors -->
<color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/colors_car.xml b/packages/SystemUI/res/values/colors_car.xml
index cb3abb9..49bfb25 100644
--- a/packages/SystemUI/res/values/colors_car.xml
+++ b/packages/SystemUI/res/values/colors_car.xml
@@ -25,4 +25,7 @@
<color name="car_user_switcher_name_text_color">@color/car_body1_light</color>
<color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color>
<color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color>
+
+ <!-- colors for volume dialog tint -->
+ <color name="car_volume_dialog_tint">@color/car_tint</color>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1aee7bc..9a3bdf2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -867,6 +867,8 @@
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
+ <!-- The start margin of quick scrub onboarding toast. -->
+ <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
<!-- The min alpha to apply to a task affiliation group color. -->
<item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
@@ -939,7 +941,7 @@
<dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
- <dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
+ <dimen name="nav_quick_scrub_track_thickness">10dp</dimen>
<!-- Navigation bar shadow params. -->
<dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 42bd66a..9fc71c8 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -166,9 +166,7 @@
long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
- for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate);
- }
+ notifyBackButtonAlphaChanged(alpha, animate);
});
} finally {
Binder.restoreCallingIdentity(token);
@@ -355,10 +353,17 @@
mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
mContext.unbindService(mOverviewServiceConnection);
mOverviewProxy = null;
+ notifyBackButtonAlphaChanged(1f, false /* animate */);
notifyConnectionChanged();
}
}
+ private void notifyBackButtonAlphaChanged(float alpha, boolean animate) {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate);
+ }
+ }
+
private void notifyConnectionChanged() {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index e6ea2d8..6d79066 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -14,6 +14,8 @@
package com.android.systemui;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.slice.SliceManager;
@@ -66,7 +68,9 @@
.setNegativeButton(R.string.slice_permission_deny, this)
.setPositiveButton(R.string.slice_permission_allow, this)
.setOnDismissListener(this)
- .show();
+ .create();
+ dialog.getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ dialog.show();
TextView t1 = dialog.getWindow().getDecorView().findViewById(R.id.text1);
t1.setText(getString(R.string.slice_permission_text_1, app2));
TextView t2 = dialog.getWindow().getDecorView().findViewById(R.id.text2);
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 31d8cbb..ad84130 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -225,9 +225,10 @@
*/
boolean shouldDismissPip() {
Point displaySize = new Point();
- mContext.getDisplay().getSize(displaySize);
- if (mBounds.bottom > displaySize.y) {
- float offscreenFraction = (float) (mBounds.bottom - displaySize.y) / mBounds.height();
+ mContext.getDisplay().getRealSize(displaySize);
+ final int y = displaySize.y - mStableInsets.bottom;
+ if (mBounds.bottom > y) {
+ float offscreenFraction = (float) (mBounds.bottom - y) / mBounds.height();
return offscreenFraction >= DISMISS_OFFSCREEN_FRACTION;
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 7afa82a..100751c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -184,9 +184,15 @@
return;
}
boolean selected = mLastExpansion == 1f;
+
+ // Disable accessibility temporarily while we update selected state purely for the
+ // marquee. This will ensure that accessibility doesn't announce the TYPE_VIEW_SELECTED
+ // event on any of the children.
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
for (int i = 0; i < mPages.size(); i++) {
mPages.get(i).setSelected(i == getCurrentItem() ? selected : false);
}
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
public void setPageListener(PageListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 086c87b..8d8e206 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -393,7 +393,20 @@
if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- mWindowManager.addView(mLayout, getWindowLayoutParams());
+ final int gravity;
+ final int x;
+ if (stringRes == R.string.recents_swipe_up_onboarding) {
+ gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ x = 0;
+ } else {
+ int layoutDirection =
+ mContext.getResources().getConfiguration().getLayoutDirection();
+ gravity = Gravity.BOTTOM | (layoutDirection == View.LAYOUT_DIRECTION_LTR
+ ? Gravity.LEFT : Gravity.RIGHT);
+ x = mContext.getResources().getDimensionPixelSize(
+ R.dimen.recents_quick_scrub_onboarding_margin_start);
+ }
+ mWindowManager.addView(mLayout, getWindowLayoutParams(gravity, x));
mLayout.setAlpha(0);
mLayout.animate()
.alpha(1f)
@@ -459,19 +472,19 @@
pw.println(" }");
}
- private WindowManager.LayoutParams getWindowLayoutParams() {
+ private WindowManager.LayoutParams getWindowLayoutParams(int gravity, int x) {
int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
- 0, -mNavBarHeight / 2,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ x, -mNavBarHeight / 2,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
flags,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("RecentsOnboarding");
- lp.gravity = Gravity.BOTTOM;
+ lp.gravity = gravity;
return lp;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index f30fa6b..d647e21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -710,6 +710,8 @@
updateClickAndFocus();
if (mNotificationParent != null) {
setOverrideTintColor(NO_COLOR, 0.0f);
+ // Let's reset the distance to top roundness, as this isn't applied to group children
+ setDistanceToTopRoundness(NO_ROUNDNESS);
mNotificationParent.updateBackgroundForGroupState();
}
updateIconVisibilities();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 29c3ebd..ae8d844 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -36,6 +36,7 @@
*/
public abstract class ExpandableView extends FrameLayout {
+ public static final float NO_ROUNDNESS = -1;
protected OnHeightChangedListener mOnHeightChangedListener;
private int mActualHeight;
protected int mClipTopAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 03791c7..91a4dda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -182,6 +182,9 @@
}
}
if (mReplyAction != null) {
+ // Let's reset the view on update, assuming the new pending intent isn't cancelled
+ // anymore. The color filter automatically resets when it's updated.
+ mReplyAction.setEnabled(true);
performOnPendingIntentCancellation(mReplyAction, () -> {
if (mReplyAction != null && mReplyAction.isEnabled()) {
mReplyAction.setEnabled(false);
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 8ede224..879ac92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -16,11 +16,8 @@
package com.android.systemui.statusbar.notification;
-import android.util.ArraySet;
import android.util.Pools;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ProgressBar;
@@ -411,7 +408,8 @@
mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
// Remove local translations
- mOwnPosition[1] -= MessagingPropertyAnimator.getLocalTranslationY(mTransformedView);
+ mOwnPosition[1] -= MessagingPropertyAnimator.getTop(mTransformedView)
+ - MessagingPropertyAnimator.getLayoutTop(mTransformedView);
return mOwnPosition;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 3c0b226..894ea62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -114,6 +114,10 @@
return mVisibility != null ? mVisibility : View.VISIBLE;
}
+ public boolean isVisible() {
+ return getVisibility() == View.VISIBLE;
+ }
+
public float getAlpha() {
return mAlpha != null ? mAlpha : 1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index f631ef8..a3cba2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -336,13 +336,14 @@
int x = (int) event.getX();
int y = (int) event.getY();
mDownHitTarget = HIT_TARGET_NONE;
- if (mBackButtonBounds.contains(x, y)) {
+ if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_BACK;
- } else if (mHomeButtonBounds.contains(x, y)) {
+ } else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_HOME;
- } else if (mRecentsButtonBounds.contains(x, y)) {
+ } else if (getRecentsButton().isVisible() && mRecentsButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_OVERVIEW;
- } else if (mRotationButtonBounds.contains(x, y)) {
+ } else if (getRotateSuggestionButton().isVisible()
+ && mRotationButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_ROTATION;
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index bdd96d5..ea1b980 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -29,14 +29,13 @@
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.util.FloatProperty;
@@ -55,6 +54,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.system.NavigationBarCompat;
+import com.android.internal.graphics.ColorUtils;
/**
* Class to detect gestures on the navigation bar and implement quick scrub.
@@ -63,7 +63,8 @@
private static final String TAG = "QuickStepController";
private static final int ANIM_IN_DURATION_MS = 150;
- private static final int ANIM_OUT_DURATION_MS = 100;
+ private static final int ANIM_OUT_DURATION_MS = 134;
+ private static final float TRACK_SCALE = 0.95f;
private NavigationBarView mNavigationBarView;
@@ -76,6 +77,7 @@
private boolean mIsVertical;
private boolean mIsRTL;
private float mTrackAlpha;
+ private float mTrackScale = TRACK_SCALE;
private int mLightTrackColor;
private int mDarkTrackColor;
private float mDarkIntensity;
@@ -85,7 +87,7 @@
private final Handler mHandler = new Handler();
private final Rect mTrackRect = new Rect();
- private final Paint mTrackPaint = new Paint();
+ private final Drawable mTrackDrawable;
private final OverviewProxyService mOverviewEventSender;
private final int mTrackThickness;
private final int mTrackEndPadding;
@@ -108,6 +110,20 @@
}
};
+ private final FloatProperty<QuickStepController> mTrackScaleProperty =
+ new FloatProperty<QuickStepController>("TrackScale") {
+ @Override
+ public void setValue(QuickStepController controller, float scale) {
+ mTrackScale = scale;
+ mNavigationBarView.invalidate();
+ }
+
+ @Override
+ public Float get(QuickStepController controller) {
+ return mTrackScale;
+ }
+ };
+
private final FloatProperty<QuickStepController> mNavBarAlphaProperty =
new FloatProperty<QuickStepController>("NavBarAlpha") {
@Override
@@ -139,7 +155,7 @@
mOverviewEventSender = Dependency.get(OverviewProxyService.class);
mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
- mTrackPaint.setAlpha(0);
+ mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate();
}
public void setComponents(NavigationBarView navigationBarView) {
@@ -296,9 +312,17 @@
}
int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
mDarkTrackColor);
- mTrackPaint.setColor(color);
- mTrackPaint.setAlpha((int) (mTrackPaint.getAlpha() * mTrackAlpha));
- canvas.drawRect(mTrackRect, mTrackPaint);
+ int colorAlpha = ColorUtils.setAlphaComponent(color,
+ (int) (Color.alpha(color) * mTrackAlpha));
+ mTrackDrawable.setTint(colorAlpha);
+
+ // Scale the track, but apply the inverse scale from the nav bar
+ canvas.save();
+ canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
+ 1f / mNavigationBarView.getScaleY(),
+ mTrackRect.centerX(), mTrackRect.centerY());
+ mTrackDrawable.draw(canvas);
+ canvas.restore();
}
@Override
@@ -322,6 +346,7 @@
x2 = x1 + width - 2 * mTrackEndPadding;
}
mTrackRect.set(x1, y1, x2, y2);
+ mTrackDrawable.setBounds(mTrackRect);
}
@Override
@@ -387,7 +412,9 @@
mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
- ObjectAnimator trackAnimator = ObjectAnimator.ofFloat(this, mTrackAlphaProperty, 1f);
+ ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
+ PropertyValuesHolder.ofFloat(mTrackScaleProperty, 1f));
trackAnimator.setInterpolator(ALPHA_IN);
trackAnimator.setDuration(ANIM_IN_DURATION_MS);
ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 0f);
@@ -438,7 +465,9 @@
mTrackAnimator.cancel();
}
- ObjectAnimator trackAnimator = ObjectAnimator.ofFloat(this, mTrackAlphaProperty, 0f);
+ ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 0f),
+ PropertyValuesHolder.ofFloat(mTrackScaleProperty, TRACK_SCALE));
trackAnimator.setInterpolator(ALPHA_OUT);
trackAnimator.setDuration(ANIM_OUT_DURATION_MS);
ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 1f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 4bda017..fe86378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -174,11 +174,13 @@
|| mStatusBar.isFullScreenUserSwitcherState()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
} else if (mShowing && !mDozing) {
- mBouncer.setExpansion(expansion);
+ if (!isWakeAndUnlocking()) {
+ mBouncer.setExpansion(expansion);
+ }
if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking
&& mStatusBar.isKeyguardCurrentlySecure()
&& !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
- mBouncer.show(false /* resetSecuritySelection */, false /* animated */);
+ mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
}
}
}
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 4ec9ae8..b814478 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -565,10 +565,12 @@
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- mRemoteInputView.mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false);
+ // When BACK key is pressed, this method would be invoked twice.
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
+ event.getAction() == KeyEvent.ACTION_UP) {
+ defocusIfNeeded(true /* animate */);
}
- return super.dispatchKeyEvent(event);
+ return super.onKeyPreIme(keyCode, event);
}
@Override
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 f91016a..7b9e711 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -388,6 +388,7 @@
return object.getDarkAmount();
}
};
+ private ObjectAnimator mDarkAmountAnimator;
private boolean mUsingLightTheme;
private boolean mQsExpanded;
private boolean mForwardScrollable;
@@ -775,7 +776,8 @@
boolean clip = clipStart > start && clipStart < end
|| clipEnd >= start && clipEnd <= end;
clip &= !(first && mOwnScrollY == 0);
- child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0) : -1);
+ child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
+ : ExpandableView.NO_ROUNDNESS);
first = false;
}
}
@@ -3401,7 +3403,7 @@
.animateY(mShelf));
ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex;
mAnimationEvents.add(ev);
- startBackgroundFade();
+ startDarkAmountAnimation();
}
mDarkNeedsAnimation = false;
}
@@ -3979,6 +3981,9 @@
mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation);
mNeedsAnimation = true;
} else {
+ if (mDarkAmountAnimator != null) {
+ mDarkAmountAnimator.cancel();
+ }
setDarkAmount(dark ? 1f : 0f);
updateBackground();
}
@@ -4023,12 +4028,22 @@
return mDarkAmount;
}
- private void startBackgroundFade() {
- ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount,
+ private void startDarkAmountAnimation() {
+ ObjectAnimator darkAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount,
mAmbientState.isDark() ? 1f : 0);
- fadeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
- fadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
- fadeAnimator.start();
+ darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
+ darkAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ darkAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDarkAmountAnimator = null;
+ }
+ });
+ if (mDarkAmountAnimator != null) {
+ mDarkAmountAnimator.cancel();
+ }
+ mDarkAmountAnimator = darkAnimator;
+ mDarkAmountAnimator.start();
}
private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 8034345..bf962b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -344,13 +344,17 @@
int supplementalIconId, @Nullable View.OnClickListener supplementalIconOnClickListener) {
SeekbarListItem listItem = new SeekbarListItem(mContext);
listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
+ int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
listItem.setProgress(progress);
listItem.setOnSeekBarChangeListener(
new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
- listItem.setPrimaryActionIcon(mContext.getResources().getDrawable(volumeItem.icon));
+ Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+ primaryIcon.setTint(color);
+ listItem.setPrimaryActionIcon(primaryIcon);
if (supplementalIconId != 0) {
Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
+ supplementalIcon.setTint(color);
listItem.setSupplementalIcon(supplementalIcon, true,
supplementalIconOnClickListener);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 4588675..955939c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -43,8 +43,10 @@
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -90,6 +92,7 @@
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
import com.android.systemui.plugins.VolumeDialogController.StreamState;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -131,8 +134,10 @@
private final AccessibilityManagerWrapper mAccessibilityMgr;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
- private final ColorStateList mActiveTint;
- private final ColorStateList mInactiveTint;
+ private ColorStateList mActiveTint;
+ private int mActiveAlpha;
+ private ColorStateList mInactiveTint;
+ private int mInactiveAlpha;
private boolean mShowing;
private boolean mShowA11yStream;
@@ -150,8 +155,6 @@
mController = Dependency.get(VolumeDialogController.class);
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
- mActiveTint = Utils.getColorAccent(mContext);
- mInactiveTint = loadColorStateList(R.color.volume_slider_inactive);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
}
@@ -224,6 +227,11 @@
return true;
});
+ mActiveTint = Utils.getColorAccent(mContext);
+ mActiveAlpha = Color.alpha(mActiveTint.getDefaultColor());
+ mInactiveTint = Utils.getColorAttr(mContext, android.R.attr.colorForeground);
+ mInactiveAlpha = getAlphaAttr(android.R.attr.secondaryContentAlpha);
+
mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
mRinger = mDialog.findViewById(R.id.ringer);
mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
@@ -263,8 +271,11 @@
return mDialogView;
}
- private ColorStateList loadColorStateList(int colorResId) {
- return ColorStateList.valueOf(mContext.getColor(colorResId));
+ private int getAlphaAttr(int attr) {
+ TypedArray ta = mContext.obtainStyledAttributes(new int[]{attr});
+ float alpha = ta.getFloat(0, 0);
+ ta.recycle();
+ return (int) (alpha * 255);
}
private boolean isLandscape() {
@@ -890,12 +901,16 @@
if (isActive) {
row.slider.requestFocus();
}
- final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveTint
- : mInactiveTint;
+ boolean useActiveColoring = isActive && row.slider.isEnabled();
+ final ColorStateList tint = useActiveColoring ? mActiveTint : mInactiveTint;
+ final int alpha = useActiveColoring ? mActiveAlpha : mInactiveAlpha;
if (tint == row.cachedTint) return;
row.slider.setProgressTintList(tint);
row.slider.setThumbTintList(tint);
+ row.slider.setProgressBackgroundTintList(tint);
+ row.slider.setAlpha(((float) alpha) / 255);
row.icon.setImageTintList(tint);
+ row.icon.setImageAlpha(alpha);
row.cachedTint = tint;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 8340ab2..85135ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -16,14 +16,12 @@
package com.android.systemui.statusbar.phone;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -170,6 +168,15 @@
verify(mBouncer, never()).setExpansion(eq(0.5f));
}
+ @Test
+ public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() {
+ when(mFingerprintUnlockController.getMode())
+ .thenReturn(FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE,
+ false /* tracking */);
+ verify(mBouncer, never()).setExpansion(anyFloat());
+ }
+
private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
public TestableStatusBarKeyguardViewManager(Context context,
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 3beebcb..aa86ea8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -812,11 +812,12 @@
resOps = new ArrayList<>();
for (int j=0; j<pkgOps.size(); j++) {
Op curOp = pkgOps.valueAt(j);
- long duration = curOp.duration == -1
+ final boolean running = curOp.duration == -1;
+ long duration = running
? (elapsedNow - curOp.startRealtime)
: curOp.duration;
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, (int) duration, curOp.proxyUid,
+ curOp.rejectTime, (int) duration, running, curOp.proxyUid,
curOp.proxyPackageName));
}
} else {
@@ -826,11 +827,12 @@
if (resOps == null) {
resOps = new ArrayList<>();
}
- long duration = curOp.duration == -1
+ final boolean running = curOp.duration == -1;
+ final long duration = running
? (elapsedNow - curOp.startRealtime)
: curOp.duration;
resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, (int) duration, curOp.proxyUid,
+ curOp.rejectTime, (int) duration, running, curOp.proxyUid,
curOp.proxyPackageName));
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 7b02a4f..c5ab932 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1950,7 +1950,8 @@
return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
+ "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
: " background")
- + ")" + " " + mRealRequest + "]";
+ + ")" + " " + mRealRequest + " "
+ + mReceiver.mWorkSource + "]";
}
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index ede870f..95e5518 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -76,17 +76,35 @@
private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
- private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f;
- private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f;
- private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f;
- private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f;
+ // Scale levels. Each level is defined as the delta between the current setting and the default
+ // intensity for that type of vibration (i.e. current - default).
+ private static final int SCALE_VERY_LOW = -2;
+ private static final int SCALE_LOW = -1;
+ private static final int SCALE_NONE = 0;
+ private static final int SCALE_HIGH = 1;
+ private static final int SCALE_VERY_HIGH = 2;
- private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255
- private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255
+ // Gamma adjustments for scale levels.
+ private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
+ private static final float SCALE_LOW_GAMMA = 1.5f;
+ private static final float SCALE_NONE_GAMMA = 1.0f;
+ private static final float SCALE_HIGH_GAMMA = 0.5f;
+ private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
+
+ // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
+ // max amplitude.
+ private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
+ private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
// If a vibration is playing for longer than 5s, it's probably not haptic feedback.
private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
+
+ // A mapping from the intensity adjustment to the scaling to apply, where the intensity
+ // adjustment is defined as the delta between the default intensity level and the user selected
+ // intensity level. It's important that we apply the scaling on the delta between the two so
+ // that the default intensity level applies no scaling to application provided effects.
+ private final SparseArray<ScaleLevel> mScaleLevels;
private final LinkedList<VibrationInfo> mPreviousVibrations;
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -180,6 +198,8 @@
case VibrationEffect.EFFECT_DOUBLE_CLICK:
case VibrationEffect.EFFECT_HEAVY_CLICK:
case VibrationEffect.EFFECT_TICK:
+ case VibrationEffect.EFFECT_POP:
+ case VibrationEffect.EFFECT_THUD:
return true;
default:
Slog.w(TAG, "Unknown prebaked vibration effect, "
@@ -254,6 +274,25 @@
}
}
+ private static final class ScaleLevel {
+ public final float gamma;
+ public final int maxAmplitude;
+
+ public ScaleLevel(float gamma) {
+ this(gamma, VibrationEffect.MAX_AMPLITUDE);
+ }
+
+ public ScaleLevel(float gamma, int maxAmplitude) {
+ this.gamma = gamma;
+ this.maxAmplitude = maxAmplitude;
+ }
+
+ @Override
+ public String toString() {
+ return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
+ }
+ }
+
VibratorService(Context context) {
vibratorInit();
// Reset the hardware to a default state, in case this is a runtime
@@ -295,11 +334,19 @@
VibrationEffect tickEffect = createEffectFromResource(
com.android.internal.R.array.config_clockTickVibePattern);
- mFallbackEffects = new SparseArray<VibrationEffect>();
+ mFallbackEffects = new SparseArray<>();
mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
+
+ mScaleLevels = new SparseArray<>();
+ mScaleLevels.put(SCALE_VERY_LOW,
+ new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
+ mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
+ mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
+ mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
+ mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
}
private VibrationEffect createEffectFromResource(int resId) {
@@ -675,41 +722,35 @@
return;
}
- final float gamma;
- final int maxAmplitude;
+ final int defaultIntensity;
if (vib.isNotification() || vib.isRingtone()) {
- if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
- gamma = GAMMA_SCALE_FACTOR_MINIMUM;
- maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY;
- } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) {
- gamma = GAMMA_SCALE_FACTOR_LOW;
- maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
- } else {
- gamma = GAMMA_SCALE_FACTOR_NONE;
- maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
- }
+ defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
+ } else if (vib.isHapticFeedback()) {
+ defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
} else {
- if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
- gamma = GAMMA_SCALE_FACTOR_LOW;
- maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
- } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) {
- gamma = GAMMA_SCALE_FACTOR_HIGH;
- maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
- } else {
- gamma = GAMMA_SCALE_FACTOR_NONE;
- maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
- }
+ // If we don't know what kind of vibration we're playing then just skip scaling for
+ // now.
+ return;
+ }
+
+ final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
+ if (scale == null) {
+ // We should have scaling levels for all cases, so not being able to scale because of a
+ // missing level is unexpected.
+ Slog.e(TAG, "No configured scaling level!"
+ + " (current=" + intensity + ", default= " + defaultIntensity + ")");
+ return;
}
VibrationEffect scaledEffect = null;
if (vib.effect instanceof VibrationEffect.OneShot) {
VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
- scaledEffect = oneShot.scale(gamma, maxAmplitude);
+ scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
} else if (vib.effect instanceof VibrationEffect.Waveform) {
VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
waveform = waveform.resolve(mDefaultVibrationAmplitude);
- scaledEffect = waveform.scale(gamma, maxAmplitude);
+ scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
} else {
Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4c2a940..ca715b5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -119,7 +119,7 @@
// How long the startForegroundService() grace period is to get around to
// calling startForeground() before we ANR + stop it.
- static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000;
+ static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
final ActivityManagerService mAm;
@@ -501,6 +501,18 @@
}
}
+ // At this point we've applied allowed-to-start policy based on whether this was
+ // an ordinary startService() or a startForegroundService(). Now, only require that
+ // the app follow through on the startForegroundService() -> startForeground()
+ // contract if it actually targets O+.
+ if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
+ if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) {
+ Slog.i(TAG, "startForegroundService() but host targets "
+ + r.appInfo.targetSdkVersion + " - not requiring startForeground()");
+ }
+ fgRequired = false;
+ }
+
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8e87ebd..9bc5829 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12925,6 +12925,8 @@
// about the process state of the isolated UID *before* it is registered with the
// owning application.
mBatteryStatsService.addIsolatedUid(uid, info.uid);
+ StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
+ StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
}
final ProcessRecord r = new ProcessRecord(this, stats, info, proc, uid);
if (!mBooted && !mBooting
@@ -15174,6 +15176,7 @@
public void onLimitReached(int uid) {
Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ Process.myUid());
+ Binder.dumpProxyDebugInfo();
if (uid == Process.SYSTEM_UID) {
Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
} else {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ef5a5a3..d456f62 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -115,6 +115,7 @@
import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
import static com.android.server.am.ActivityRecordProto.PROC_ID;
import static com.android.server.am.ActivityRecordProto.STATE;
+import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
import static com.android.server.am.ActivityRecordProto.VISIBLE;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -2412,11 +2413,16 @@
}
// Compute configuration based on max supported width and height.
- outBounds.set(0, 0, maxActivityWidth, maxActivityHeight);
- // Position the activity frame on the opposite side of the nav bar.
- final int navBarPosition = service.mWindowManager.getNavBarPosition();
- final int left = navBarPosition == NAV_BAR_LEFT ? appBounds.right - outBounds.width() : 0;
- outBounds.offsetTo(left, 0 /* top */);
+ // Also account for the left / top insets (e.g. from display cutouts), which will be clipped
+ // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app
+ // bounds would end up too small.
+ outBounds.set(0, 0, maxActivityWidth + appBounds.left, maxActivityHeight + appBounds.top);
+
+ if (service.mWindowManager.getNavBarPosition() == NAV_BAR_LEFT) {
+ // Position the activity frame on the opposite side of the nav bar.
+ outBounds.left = appBounds.right - maxActivityWidth;
+ outBounds.right = appBounds.right;
+ }
}
boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
@@ -2980,6 +2986,7 @@
if (app != null) {
proto.write(PROC_ID, app.pid);
}
+ proto.write(TRANSLUCENT, !fullscreen);
proto.end(token);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index aaa5161..3ad461f 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1360,7 +1360,9 @@
}
void goToSleep() {
- ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ // Ensure visibility without updating configuration, as activities are about to sleep.
+ ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS,
+ false /* updateConfiguration */);
// Make sure any paused or stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
@@ -1829,12 +1831,23 @@
}
/**
- * Make sure that all activities that need to be visible (that is, they
- * currently can be seen by the user) actually are.
+ * Make sure that all activities that need to be visible in the stack (that is, they
+ * currently can be seen by the user) actually are and update their configuration.
+ */
+ final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
+ boolean preserveWindows) {
+ ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
+ true /* updateConfiguration */);
+ }
+
+ /**
+ * Ensure visibility with an option to also update the configuration of visible activities.
+ * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
+ * @see ActivityStackSupervisor#ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
*/
// TODO: Should be re-worked based on the fact that each task as a stack in most cases.
final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
- boolean preserveWindows) {
+ boolean preserveWindows, boolean updateConfiguration) {
mTopActivityOccludesKeyguard = false;
mTopDismissingKeyguardActivity = null;
mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
@@ -1886,9 +1899,7 @@
+ " finishing=" + r.finishing + " state=" + r.getState());
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
- if (r != starting) {
- // Ensure activity configuration ignoring stop state since we are
- // becoming visible.
+ if (r != starting && updateConfiguration) {
r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
true /* ignoreStopState */);
}
@@ -2608,25 +2619,16 @@
boolean notUpdated = true;
if (mStackSupervisor.isFocusedStack(this)) {
-
- // We have special rotation behavior when Keyguard is locked. Make sure all
- // activity visibilities are set correctly as well as the transition is updated
- // if needed to get the correct rotation behavior.
+ // We have special rotation behavior when here is some active activity that
+ // requests specific orientation or Keyguard is locked. Make sure all activity
+ // visibilities are set correctly as well as the transition is updated if needed
+ // to get the correct rotation behavior. Otherwise the following call to update
+ // the orientation may cause incorrect configurations delivered to client as a
+ // result of invisible window resize.
// TODO: Remove this once visibilities are set correctly immediately when
// starting an activity.
- if (mStackSupervisor.getKeyguardController().isKeyguardLocked()) {
- mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */,
- 0 /* configChanges */, false /* preserveWindows */);
- }
- final Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mStackSupervisor.getDisplayOverrideConfiguration(mDisplayId),
- next.mayFreezeScreenLocked(next.app) ? next.appToken : null,
- mDisplayId);
- if (config != null) {
- next.frozenBeforeDestroy = true;
- }
- notUpdated = !mService.updateDisplayOverrideConfigurationLocked(config, next,
- false /* deferResume */, mDisplayId);
+ notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
+ true /* markFrozenIfConfigChanged */, false /* deferResume */);
}
if (notUpdated) {
@@ -3834,7 +3836,8 @@
if (finishingActivityInNonFocusedStack) {
// Finishing activity that was in paused state and it was in not currently focused
// stack, need to make something visible in its place.
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ mStackSupervisor.ensureVisibilityAndConfig(null, mDisplayId,
+ false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
if (activityRemoved) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7310fab..257d79d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1409,15 +1409,11 @@
// manager with a new orientation. We don't care about that, because the activity is
// not currently running so we are just restarting it anyway.
if (checkConfig) {
- final int displayId = r.getDisplayId();
- final Configuration config = mWindowManager.updateOrientationFromAppTokens(
- getDisplayOverrideConfiguration(displayId),
- r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
// configurations and trying to resume top activity of focused stack.
- mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
- displayId);
+ ensureVisibilityAndConfig(r, r.getDisplayId(),
+ false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
@@ -1630,6 +1626,31 @@
return true;
}
+ /**
+ * Ensure all activities visibility, update orientation and configuration.
+ */
+ boolean ensureVisibilityAndConfig(ActivityRecord r, int displayId,
+ boolean markFrozenIfConfigChanged, boolean deferResume) {
+ // First ensure visibility without updating the config just yet. We need this to know what
+ // activities are affecting configuration now.
+ ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */, false /* updateConfiguration */);
+
+ // Force-update the orientation from the WindowManager, since we need the true configuration
+ // to send to the client now.
+ final Configuration config = mWindowManager.updateOrientationFromAppTokens(
+ getDisplayOverrideConfiguration(displayId),
+ r != null && r.mayFreezeScreenLocked(r.app) ? r.appToken : null,
+ displayId, true /* forceUpdate */);
+ if (r != null && markFrozenIfConfigChanged && config != null) {
+ r.frozenBeforeDestroy = true;
+ }
+
+ // Update the configuration of the activities on the display.
+ return mService.updateDisplayOverrideConfigurationLocked(config, r,
+ deferResume, displayId);
+ }
+
private void logIfTransactionTooLarge(Intent intent, Bundle icicle) {
int extrasSize = 0;
if (intent != null) {
@@ -3647,8 +3668,21 @@
mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget();
}
+ /**
+ * Make sure that all activities that need to be visible in the system actually are and update
+ * their configuration.
+ */
void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
boolean preserveWindows) {
+ ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
+ true /* updateConfiguration */);
+ }
+
+ /**
+ * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
+ */
+ void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
+ boolean preserveWindows, boolean updateConfiguration) {
getKeyguardController().beginActivityVisibilityUpdate();
try {
// First the front stacks. In case any are not fullscreen and are in front of home.
@@ -3656,7 +3690,8 @@
final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
- stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
+ stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
+ updateConfiguration);
}
}
} finally {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 49fa902..094cf06 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -31,6 +31,7 @@
import android.telephony.TelephonyManager;
import android.util.IntArray;
import android.util.Slog;
+import android.util.StatsLog;
import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
@@ -367,6 +368,8 @@
// Clean up any UIDs if necessary.
synchronized (mStats) {
for (int uid : uidsToRemove) {
+ StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, -1, uid,
+ StatsLog.ISOLATED_UID_CHANGED__EVENT__REMOVED);
mStats.removeIsolatedUidLocked(uid);
}
mStats.clearPendingRemovedUids();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cddb05e..1c5dcce 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3312,6 +3312,9 @@
.append(Binder.getCallingPid()).toString();
synchronized (mBluetoothA2dpEnabledLock) {
+ if (mBluetoothA2dpEnabled == on) {
+ return;
+ }
mBluetoothA2dpEnabled = on;
sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
AudioSystem.FOR_MEDIA,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 0cba76b..5681367 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -31,6 +32,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -249,11 +251,11 @@
case Constants.MESSAGE_SET_MENU_LANGUAGE:
return handleSetMenuLanguage(message);
case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
- return handleGivePhysicalAddress();
+ return handleGivePhysicalAddress(null);
case Constants.MESSAGE_GIVE_OSD_NAME:
return handleGiveOsdName(message);
case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
- return handleGiveDeviceVendorId();
+ return handleGiveDeviceVendorId(null);
case Constants.MESSAGE_GET_CEC_VERSION:
return handleGetCecVersion(message);
case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
@@ -325,23 +327,23 @@
}
@ServiceThreadOnly
- protected boolean handleGivePhysicalAddress() {
+ protected boolean handleGivePhysicalAddress(@Nullable SendMessageCallback callback) {
assertRunOnServiceThread();
int physicalAddress = mService.getPhysicalAddress();
HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, physicalAddress, mDeviceType);
- mService.sendCecCommand(cecMessage);
+ mService.sendCecCommand(cecMessage, callback);
return true;
}
@ServiceThreadOnly
- protected boolean handleGiveDeviceVendorId() {
+ protected boolean handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) {
assertRunOnServiceThread();
int vendorId = mService.getVendorId();
HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
mAddress, vendorId);
- mService.sendCecCommand(cecMessage);
+ mService.sendCecCommand(cecMessage, callback);
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 8c00be5..4ad51de 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -22,7 +22,7 @@
/**
* A helper class to validates {@link HdmiCecMessage}.
*/
-public final class HdmiCecMessageValidator {
+public class HdmiCecMessageValidator {
private static final String TAG = "HdmiCecMessageValidator";
static final int OK = 0;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index ba6da05..a1753e5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -68,6 +68,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
@@ -290,6 +291,9 @@
@Nullable
private PowerManager mPowerManager;
+ @Nullable
+ private Looper mIoLooper;
+
// Last input port before switching to the MHL port. Should switch back to this port
// when the mobile device sends the request one touch play with off.
// Gets invalidated if we go to other port/input.
@@ -383,13 +387,18 @@
@Override
public void onStart() {
- mIoThread.start();
+ if (mIoLooper == null) {
+ mIoThread.start();
+ mIoLooper = mIoThread.getLooper();
+ }
mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
mProhibitMode = false;
mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true);
mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);
- mCecController = HdmiCecController.create(this);
+ if (mCecController == null) {
+ mCecController = HdmiCecController.create(this);
+ }
if (mCecController != null) {
if (mHdmiControlEnabled) {
initializeCec(INITIATED_BY_BOOT_UP);
@@ -406,7 +415,9 @@
mMhlDevices = Collections.emptyList();
initPortInfo();
- mMessageValidator = new HdmiCecMessageValidator(this);
+ if (mMessageValidator == null) {
+ mMessageValidator = new HdmiCecMessageValidator(this);
+ }
publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
if (mCecController != null) {
@@ -424,6 +435,11 @@
mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED);
}
+ @VisibleForTesting
+ void setCecController(HdmiCecController cecController) {
+ mCecController = cecController;
+ }
+
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -747,8 +763,19 @@
*
* <p>Declared as package-private.
*/
+ @Nullable
Looper getIoLooper() {
- return mIoThread.getLooper();
+ return mIoLooper;
+ }
+
+ @VisibleForTesting
+ void setIoLooper(Looper ioLooper) {
+ mIoLooper = ioLooper;
+ }
+
+ @VisibleForTesting
+ void setMessageValidator(HdmiCecMessageValidator messageValidator) {
+ mMessageValidator = messageValidator;
}
/**
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index b213ee60..b90c12a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1016,26 +1016,25 @@
locationListener = mFusedLocationListener;
}
- if (!locationManager.isProviderEnabled(provider)) {
- Log.w(TAG, "Unable to request location since " + provider
- + " provider does not exist or is not enabled.");
- return;
- }
-
Log.i(TAG,
String.format(
"GNSS HAL Requesting location updates from %s provider for %d millis.",
provider, durationMillis));
- locationManager.requestLocationUpdates(provider,
- LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
- locationListener, mHandler.getLooper());
- locationListener.numLocationUpdateRequest++;
- mHandler.postDelayed(() -> {
- if (--locationListener.numLocationUpdateRequest == 0) {
- Log.i(TAG, String.format("Removing location updates from %s provider.", provider));
- locationManager.removeUpdates(locationListener);
- }
- }, durationMillis);
+ try {
+ locationManager.requestLocationUpdates(provider,
+ LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
+ locationListener, mHandler.getLooper());
+ locationListener.numLocationUpdateRequest++;
+ mHandler.postDelayed(() -> {
+ if (--locationListener.numLocationUpdateRequest == 0) {
+ Log.i(TAG,
+ String.format("Removing location updates from %s provider.", provider));
+ locationManager.removeUpdates(locationListener);
+ }
+ }, durationMillis);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Unable to request location.", e);
+ }
}
private void injectBestLocation(Location location) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 384efdd..a7df0e2 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -95,9 +95,8 @@
// State guarded by mLock.
private final Object mLock = new Object();
- private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
- private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
- new ArrayMap<IBinder, ClientRecord>();
+ private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
+ private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
private int mCurrentUserId = -1;
private final IAudioService mAudioService;
private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
@@ -106,7 +105,7 @@
private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray();
private final BroadcastReceiver mReceiver = new MediaRouterServiceBroadcastReceiver();
- BluetoothDevice mBluetoothDevice;
+ BluetoothDevice mActiveBluetoothDevice;
int mAudioRouteMainType = AudioRoutesInfo.MAIN_SPEAKER;
boolean mGlobalBluetoothA2dpOn = false;
@@ -180,7 +179,8 @@
| AudioRoutesInfo.MAIN_HEADPHONES
| AudioRoutesInfo.MAIN_USB)) == 0) {
// headset was plugged out.
- mGlobalBluetoothA2dpOn = mBluetoothDevice != null;
+ mGlobalBluetoothA2dpOn = (newRoutes.bluetoothName != null
+ || mActiveBluetoothDevice != null);
} else {
// headset was plugged in.
mGlobalBluetoothA2dpOn = false;
@@ -197,7 +197,7 @@
Slog.w(TAG, "RemoteException in the audio service.");
}
- IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+ IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
}
@@ -406,12 +406,14 @@
void restoreBluetoothA2dp() {
try {
- boolean a2dpOn = false;
+ boolean a2dpOn;
+ BluetoothDevice btDevice;
synchronized (mLock) {
a2dpOn = mGlobalBluetoothA2dpOn;
+ btDevice = mActiveBluetoothDevice;
}
// We don't need to change a2dp status when bluetooth is not connected.
- if (mBluetoothDevice != null) {
+ if (btDevice != null) {
Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")");
mAudioService.setBluetoothA2dpOn(a2dpOn);
}
@@ -653,17 +655,11 @@
final class MediaRouterServiceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
- BluetoothProfile.STATE_DISCONNECTED);
- if (state == BluetoothProfile.STATE_DISCONNECTED) {
- mGlobalBluetoothA2dpOn = false;
- mBluetoothDevice = null;
- } else if (state == BluetoothProfile.STATE_CONNECTED) {
- mGlobalBluetoothA2dpOn = true;
- mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- // To ensure that BT A2DP is on, call restoreBluetoothA2dp().
- restoreBluetoothA2dp();
+ if (intent.getAction().equals(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED)) {
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ synchronized (mLock) {
+ mActiveBluetoothDevice = btDevice;
+ mGlobalBluetoothA2dpOn = btDevice != null;
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b698b92..ba73c7e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17294,17 +17294,6 @@
+ "Persistent apps are not updateable.");
return;
}
- // Prevent apps from downgrading their targetSandbox.
- final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
- final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
- if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
- res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
- "Package " + pkg.packageName + " new target sandbox "
- + newTargetSandbox + " is incompatible with the previous value of"
- + oldTargetSandbox + ".");
- return;
- }
-
// Prevent installing of child packages
if (oldPackage.parentPackage != null) {
res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 199098b..781faa7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6153,7 +6153,9 @@
sendSystemKeyToStatusBarAsync(event.getKeyCode());
TelecomManager telecomManager = getTelecommService();
- if (telecomManager != null) {
+ if (telecomManager != null && !mHandleVolumeKeysInWM) {
+ // When {@link #mHandleVolumeKeysInWM} is set, volume key events
+ // should be dispatched to WM.
if (telecomManager.isRinging()) {
// If an incoming call is ringing, either VOLUME key means
// "silence ringer". We handle these keys here, rather than
@@ -6922,7 +6924,7 @@
} else {
if (DEBUG_WAKEUP) Slog.d(TAG,
"null mKeyguardDelegate: setting mKeyguardDrawComplete.");
- finishKeyguardDrawn();
+ mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
}
}
}
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 91ef3d4..ed2b79e 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -392,7 +392,7 @@
mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
- mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, true);
+ mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false);
// Get default value from Settings.Secure
final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e637df4..0ba5a56 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1297,7 +1297,7 @@
// going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
// an Activity in another task being started in the wrong orientation during the transition.
if (!(sendingToBottom || mService.mClosingApps.contains(this))
- && (isVisible() || mService.mOpeningApps.contains(this) || isOnTop())) {
+ && (isVisible() || mService.mOpeningApps.contains(this))) {
return mOrientation;
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index b8431b1..65c8e96 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -22,7 +22,9 @@
import static com.android.server.wm.AnimationSpecProto.ALPHA;
import android.graphics.Rect;
+import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.Surface;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
@@ -171,14 +173,18 @@
*/
private DimState getDimState(WindowContainer container) {
if (mDimState == null) {
- final SurfaceControl ctl = makeDimLayer();
- mDimState = new DimState(ctl);
- /**
- * See documentation on {@link #dimAbove} to understand lifecycle management of Dim's
- * via state resetting for Dim's with containers.
- */
- if (container == null) {
- mDimState.mDontReset = true;
+ try {
+ final SurfaceControl ctl = makeDimLayer();
+ mDimState = new DimState(ctl);
+ /**
+ * See documentation on {@link #dimAbove} to understand lifecycle management of
+ * Dim's via state resetting for Dim's with containers.
+ */
+ if (container == null) {
+ mDimState.mDontReset = true;
+ }
+ } catch (Surface.OutOfResourcesException e) {
+ Log.w(TAG, "OutOfResourcesException creating dim surface");
}
}
@@ -189,6 +195,11 @@
private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
float alpha) {
final DimState d = getDimState(container);
+
+ if (d == null) {
+ return;
+ }
+
if (container != null) {
// The dim method is called from WindowState.prepareSurfaces(), which is always called
// in the correct Z from lowest Z to highest. This ensures that the dim layer is always
@@ -208,10 +219,11 @@
* @param t A Transaction in which to finish the dim.
*/
void stopDim(SurfaceControl.Transaction t) {
- DimState d = getDimState(null);
- t.hide(d.mDimLayer);
- d.isVisible = false;
- d.mDontReset = false;
+ if (mDimState != null) {
+ t.hide(mDimState.mDimLayer);
+ mDimState.isVisible = false;
+ mDimState.mDontReset = false;
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f3423c6..b59e728 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -944,33 +944,50 @@
/**
* Update rotation of the display.
*
- * Returns true if the rotation has been changed. In this case YOU MUST CALL
- * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
+ * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
+ * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
*/
boolean updateRotationUnchecked() {
- if (mService.mDeferredRotationPauseCount > 0) {
- // Rotation updates have been paused temporarily. Defer the update until
- // updates have been resumed.
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
- return false;
- }
+ return updateRotationUnchecked(false /* forceUpdate */);
+ }
- ScreenRotationAnimation screenRotationAnimation =
- mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
- if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
- // Rotation updates cannot be performed while the previous rotation change
- // animation is still in progress. Skip this update. We will try updating
- // again after the animation is finished and the display is unfrozen.
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
- return false;
- }
- if (mService.mDisplayFrozen) {
- // Even if the screen rotation animation has finished (e.g. isAnimating
- // returns false), there is still some time where we haven't yet unfrozen
- // the display. We also need to abort rotation here.
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Deferring rotation, still finishing previous rotation");
- return false;
+ /**
+ * Update rotation of the display with an option to force the update.
+ * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
+ * orientation because we're waiting for some rotation to finish or display
+ * to unfreeze, which results in configuration of the previously visible
+ * activity being applied to a newly visible one. Forcing the rotation
+ * update allows to workaround this issue.
+ * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
+ * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
+ */
+ boolean updateRotationUnchecked(boolean forceUpdate) {
+ ScreenRotationAnimation screenRotationAnimation;
+ if (!forceUpdate) {
+ if (mService.mDeferredRotationPauseCount > 0) {
+ // Rotation updates have been paused temporarily. Defer the update until
+ // updates have been resumed.
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
+ return false;
+ }
+
+ screenRotationAnimation =
+ mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+ if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+ // Rotation updates cannot be performed while the previous rotation change
+ // animation is still in progress. Skip this update. We will try updating
+ // again after the animation is finished and the display is unfrozen.
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
+ return false;
+ }
+ if (mService.mDisplayFrozen) {
+ // Even if the screen rotation animation has finished (e.g. isAnimating
+ // returns false), there is still some time where we haven't yet unfrozen
+ // the display. We also need to abort rotation here.
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+ "Deferring rotation, still finishing previous rotation");
+ return false;
+ }
}
if (!mService.mDisplayEnabled) {
@@ -992,7 +1009,7 @@
if (mayRotateSeamlessly) {
final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
- if (seamlessRotated != null) {
+ if (seamlessRotated != null && !forceUpdate) {
// We can't rotate (seamlessly or not) while waiting for the last seamless rotation
// to complete (that is, waiting for windows to redraw). It's tempting to check
// w.mSeamlessRotationCount but that could be incorrect in the case of
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 7211533..2bfff26 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -206,6 +206,9 @@
}
}
});
+ a.mAnim = anim;
+ mRunningAnimations.put(a.mLeash, a);
+
anim.start();
if (a.mAnimSpec.canSkipFirstFrame()) {
// If we can skip the first frame, we start one frame later.
@@ -215,8 +218,6 @@
// Immediately start the animation by manually applying an animation frame. Otherwise, the
// start time would only be set in the next frame, leading to a delay.
anim.doAnimationFrame(mChoreographer.getFrameTime());
- a.mAnim = anim;
- mRunningAnimations.put(a.mLeash, a);
}
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f73c2db..35e4092 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -29,6 +29,7 @@
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
import android.annotation.IntDef;
+import android.app.IActivityManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Looper;
@@ -93,6 +94,7 @@
static final float MIN_ASPECT = 1.2f;
private final WindowManagerService mService;
+ private final IActivityManager mActivityManager;
private WindowPositionerEventReceiver mInputEventReceiver;
private Display mDisplay;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -165,7 +167,7 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"wm.TaskPositioner.resizeTask");
try {
- mService.mActivityManager.resizeTask(
+ mActivityManager.resizeTask(
mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
} catch (RemoteException e) {
}
@@ -198,7 +200,7 @@
if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
// We were using fullscreen surface during resizing. Request
// resizeTask() one last time to restore surface to window size.
- mService.mActivityManager.resizeTask(
+ mActivityManager.resizeTask(
mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
}
} catch(RemoteException e) {}
@@ -216,9 +218,15 @@
}
}
+ @VisibleForTesting
+ TaskPositioner(WindowManagerService service, IActivityManager activityManager) {
+ mService = service;
+ mActivityManager = activityManager;
+ }
+
/** Use {@link #create(WindowManagerService)} instead **/
TaskPositioner(WindowManagerService service) {
- mService = service;
+ this(service, service.mActivityManager);
}
@VisibleForTesting
@@ -349,8 +357,7 @@
startDrag(resize, preserveOrientation, startX, startY, mTmpRect);
}
- @VisibleForTesting
- void startDrag(boolean resize, boolean preserveOrientation,
+ private void startDrag(boolean resize, boolean preserveOrientation,
float startX, float startY, Rect startBounds) {
mCtrlType = CTRL_NONE;
mStartDragX = startX;
@@ -394,7 +401,7 @@
// guaranteed to happen before subsequent drag resizes.
mService.mH.post(() -> {
try {
- mService.mActivityManager.resizeTask(
+ mActivityManager.resizeTask(
mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index c366e4d..7b775f5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -54,7 +54,7 @@
static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || false;
static final boolean DEBUG_WALLPAPER = false;
- static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
+ static final boolean DEBUG_WALLPAPER_LIGHT = true || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = false;
static final boolean DEBUG_SCREEN_ON = false;
static final boolean DEBUG_SCREENSHOT = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ab19b82..a2ffcae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2371,6 +2371,12 @@
@Override
public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
IBinder freezeThisOneIfNeeded, int displayId) {
+ return updateOrientationFromAppTokens(currentConfig, freezeThisOneIfNeeded, displayId,
+ false /* forceUpdate */);
+ }
+
+ public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
+ IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -2380,7 +2386,7 @@
try {
synchronized(mWindowMap) {
config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
- displayId);
+ displayId, forceUpdate);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2390,13 +2396,13 @@
}
private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId) {
+ IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
if (!mDisplayReady) {
return null;
}
Configuration config = null;
- if (updateOrientationFromAppTokensLocked(displayId)) {
+ if (updateOrientationFromAppTokensLocked(displayId, forceUpdate)) {
// If we changed the orientation but mOrientationChangeComplete is already true,
// we used seamless rotation, and we don't need to freeze the screen.
if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2444,11 +2450,15 @@
* @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
*/
boolean updateOrientationFromAppTokensLocked(int displayId) {
+ return updateOrientationFromAppTokensLocked(displayId, false /* forceUpdate */);
+ }
+
+ boolean updateOrientationFromAppTokensLocked(int displayId, boolean forceUpdate) {
long ident = Binder.clearCallingIdentity();
try {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
final int req = dc.getOrientation();
- if (req != dc.getLastOrientation()) {
+ if (req != dc.getLastOrientation() || forceUpdate) {
dc.setLastOrientation(req);
//send a message to Policy indicating orientation change to take
//action like disabling/enabling sensors etc.,
@@ -2456,12 +2466,8 @@
if (dc.isDefaultDisplay) {
mPolicy.setCurrentOrientationLw(req);
}
- if (dc.updateRotationUnchecked()) {
- // changed
- return true;
- }
+ return dc.updateRotationUnchecked(forceUpdate);
}
-
return false;
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0c9ed21..a18d34b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -87,6 +87,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
@@ -1763,7 +1764,7 @@
@Override
void onResize() {
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
- if (mHasSurface && !resizingWindows.contains(this)) {
+ if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) {
if (DEBUG_RESIZE) Slog.d(TAG, "onResize: Resizing " + this);
resizingWindows.add(this);
}
@@ -4210,10 +4211,15 @@
}
if (!mWinAnimator.mLastHidden || wasDeferred) {
mWinAnimator.hide(reason);
+ getDisplayContent().mWallpaperController.mDeferredHideWallpaper = null;
dispatchWallpaperVisibility(false);
final DisplayContent displayContent = getDisplayContent();
if (displayContent != null) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ if (DEBUG_LAYOUT_REPEATS) {
+ mService.mWindowPlacerLocked.debugLayoutRepeats("hideWallpaperWindow " + this,
+ displayContent.pendingLayoutChanges);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3eef125..561c9de 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1115,7 +1115,7 @@
setSurfaceBoundariesLocked(recoveringMemory);
- if (mIsWallpaper && !mWin.mWallpaperVisible) {
+ if (mIsWallpaper && !w.mWallpaperVisible) {
// Wallpaper is no longer visible and there is no wp target => hide it.
hide("prepareSurfaceLocked");
} else if (w.isParentWindowHidden() || !w.isOnScreen()) {
@@ -1179,6 +1179,11 @@
// LogicalDisplay.
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
FINISH_LAYOUT_REDO_ANIM);
+ if (DEBUG_LAYOUT_REPEATS) {
+ mService.mWindowPlacerLocked.debugLayoutRepeats(
+ "showSurfaceRobustlyLocked " + w,
+ mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+ }
} else {
w.setOrientationChanging(false);
}
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
index ea0fe45..7f397d6 100644
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -36,6 +38,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+
/**
* Tests app ops version upgrades
*/
@@ -107,6 +111,46 @@
verifyNoMoreInteractions(listener);
}
+ @Test
+ public void testIsRunning() throws Exception {
+ final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+ // Start the op
+ appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+
+ assertTrue("Camera should be running", isCameraOn(appOpsManager));
+
+ // Finish the op
+ appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+
+ assertFalse("Camera should not be running", isCameraOn(appOpsManager));
+ }
+
+ private boolean isCameraOn(AppOpsManager appOpsManager) {
+ List<AppOpsManager.PackageOps> packages
+ = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA});
+ // AppOpsManager can return null when there is no requested data.
+ if (packages != null) {
+ final int numPackages = packages.size();
+ for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+ AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+ List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+ if (opEntries != null) {
+ final int numOps = opEntries.size();
+ for (int opInd = 0; opInd < numOps; opInd++) {
+ AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+ if (opEntry.getOp() == AppOpsManager.OP_CAMERA) {
+ if (opEntry.isRunning()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
private static Context getContext() {
return InstrumentationRegistry.getContext();
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
new file mode 100644
index 0000000..78cb56b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2018 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.server.hdmi;
+
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID;
+import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.hardware.hdmi.HdmiPortInfo;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.os.MessageQueue;
+import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+import junit.framework.Assert;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/**
+ * Tests for {@link HdmiCecLocalDevice} class.
+ */
+public class HdmiCecLocalDeviceTest {
+
+ private static final class NativeWrapperImpl implements NativeWrapper {
+
+ @Override
+ public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
+ return 1L;
+ }
+
+ @Override
+ public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
+ byte[] body) {
+ return SendCecCommandFactory(srcAddress, dstAddress, body);
+ }
+
+ @Override
+ public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
+ return 0;
+ }
+
+ @Override
+ public void nativeClearLogicalAddress(long controllerPtr) {
+
+ }
+
+ @Override
+ public int nativeGetPhysicalAddress(long controllerPtr) {
+ return mPhysicalAddr;
+ }
+
+ @Override
+ public int nativeGetVersion(long controllerPtr) {
+ return 0;
+ }
+
+ @Override
+ public int nativeGetVendorId(long controllerPtr) {
+ return 0;
+ }
+
+ @Override
+ public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
+ return new HdmiPortInfo[0];
+ }
+
+ @Override
+ public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {
+
+ }
+
+ @Override
+ public void nativeSetLanguage(long controllerPtr, String language) {
+
+ }
+
+ @Override
+ public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
+
+ }
+
+ @Override
+ public boolean nativeIsConnected(long controllerPtr, int port) {
+ return false;
+ }
+ }
+
+ private static int SendCecCommandFactory(int srcAddress, int dstAddress, byte[] body) {
+ switch(body[0] & 0xFF) {
+ /** {@link Constants#MESSAGE_GIVE_PHYSICAL_ADDRESS} */
+ case MESSAGE_REPORT_PHYSICAL_ADDRESS:
+ case MESSAGE_DEVICE_VENDOR_ID:
+ return srcAddress == mSrcAddr &&
+ dstAddress == mDesAddr &&
+ Arrays.equals(Arrays.copyOfRange(body, 1, body.length), param)? 0 : 1;
+ default:
+ return 1;
+ }
+ }
+
+ private class MyHdmiCecLocalDevice extends HdmiCecLocalDevice {
+
+
+ protected MyHdmiCecLocalDevice(HdmiControlService service, int deviceType) {
+ super(service, deviceType);
+ }
+
+ @Override
+ protected void onAddressAllocated(int logicalAddress, int reason) {
+
+ }
+
+ @Override
+ protected int getPreferredAddress() {
+ return 0;
+ }
+
+ @Override
+ protected void setPreferredAddress(int addr) {
+
+ }
+ }
+
+ private MyHdmiCecLocalDevice mHdmiLocalDevice;
+ private HdmiControlService mHdmiControlService;
+ private HdmiCecController mHdmiCecController;
+ private TestLooper mTestLooper = new TestLooper();
+ private static int mDesAddr = -1;
+ private static int mSrcAddr = -1;
+ private static int mPhysicalAddr = 2;
+ private int callbackResult;
+ private HdmiCecMessageValidator mMessageValidator;
+ private static byte[] param;
+
+ @Before
+ public void SetUp() {
+ mHdmiControlService = new HdmiControlService(null);
+ mHdmiControlService.setIoLooper(mTestLooper.getLooper());
+ mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+ mHdmiControlService, new NativeWrapperImpl());
+ mHdmiControlService.setCecController(mHdmiCecController);
+ mHdmiLocalDevice = new MyHdmiCecLocalDevice(
+ mHdmiControlService, DEVICE_TV);
+ mMessageValidator = new HdmiCecMessageValidator(mHdmiControlService){
+ @Override
+ int isValid(HdmiCecMessage message) {
+ return HdmiCecMessageValidator.OK;
+ }
+ };
+ mHdmiControlService.setMessageValidator(mMessageValidator);
+ }
+
+ @Test
+ public void dispatchMessage_desNotValid() {
+ HdmiCecMessage msg = new HdmiCecMessage(
+ ADDR_TV, ADDR_TV, Constants.MESSAGE_CEC_VERSION, HdmiCecMessage.EMPTY_PARAM);
+ boolean handleResult = mHdmiLocalDevice.dispatchMessage(msg);
+ assertFalse(handleResult);
+ }
+
+ @Test
+ public void handleGivePhysicalAddress_success() {
+ mSrcAddr = ADDR_UNREGISTERED;
+ mDesAddr = ADDR_BROADCAST;
+ param = new byte[] {
+ (byte) ((mPhysicalAddr >> 8) & 0xFF),
+ (byte) (mPhysicalAddr & 0xFF),
+ (byte) (DEVICE_TV & 0xFF)
+ };
+ callbackResult = -1;
+ boolean handleResult = mHdmiLocalDevice.handleGivePhysicalAddress(
+ (int finalResult) -> callbackResult = finalResult);
+ mTestLooper.dispatchAll();
+ /**
+ * Test if CecMessage is sent successfully
+ * SendMessageResult#SUCCESS is defined in HAL as 0
+ */
+ assertEquals(0, callbackResult);
+ assertTrue(handleResult);
+ }
+
+ @Test
+ public void handleGiveDeviceVendorId_success() {
+ mSrcAddr = ADDR_UNREGISTERED;
+ mDesAddr = ADDR_BROADCAST;
+ /** nativeGetVendorId returns 0 */
+ param = new byte[] {
+ (byte) ((0 >> 8) & 0xFF),
+ (byte) (0 & 0xFF),
+ (byte) (0 & 0xFF)
+ };
+ callbackResult = -1;
+ mHdmiLocalDevice.handleGiveDeviceVendorId(
+ (int finalResult) -> callbackResult = finalResult);
+ mTestLooper.dispatchAll();
+ assertEquals(0, callbackResult);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 0c63cd2..f6599dc 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -202,11 +202,6 @@
assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation());
// Can specify orientation if the current orientation candidate is orientation behind.
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation(SCREEN_ORIENTATION_BEHIND));
-
- mToken.sendingToBottom = false;
- mToken.setIsOnTop(true);
- // Allow for mToken to provide orientation hidden if on top and not being sent to bottom.
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
index 7bf7dd7..4447b26 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.app.IActivityManager;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -27,7 +28,10 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
+import org.mockito.Mockito;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
@@ -54,6 +58,8 @@
private int mMinVisibleWidth;
private int mMinVisibleHeight;
private TaskPositioner mPositioner;
+ private WindowState mWindow;
+ private Rect mDimBounds = new Rect();
@Before
public void setUp() throws Exception {
@@ -69,8 +75,20 @@
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
- mPositioner = TaskPositioner.create(sWm);
+ mPositioner = new TaskPositioner(sWm, Mockito.mock(IActivityManager.class));
mPositioner.register(mDisplayContent);
+
+ mWindow = Mockito.spy(createWindow(null, TYPE_BASE_APPLICATION, "window"));
+ final Task task = Mockito.spy(mWindow.getTask());
+ Mockito.when(mWindow.getTask()).thenReturn(task);
+
+ Mockito.doAnswer(invocation -> {
+ final Rect rect = (Rect) invocation.getArguments()[0];
+ rect.set(mDimBounds);
+ return (Void) null;
+ }).when(task).getDimBounds(Mockito.any(Rect.class));
+
+ mWindow.getStack().setWindowingMode(WINDOWING_MODE_FREEFORM);
}
@Test
@@ -94,14 +112,14 @@
* as does some basic tests (e.g. dragging in Y only will keep X stable).
*/
@Test
- @Ignore
public void testBasicFreeWindowResizing() throws Exception {
final Rect r = new Rect(100, 220, 700, 520);
final int midY = (r.top + r.bottom) / 2;
+ mDimBounds.set(r);
// Start a drag resize starting upper left.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
assertBoundsEquals(r, mPositioner.getWindowDragBounds());
// Drag to a good landscape size.
@@ -127,8 +145,8 @@
mPositioner.getWindowDragBounds());
// Start a drag resize left and see that only the left coord changes..
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
// Drag to the left.
mPositioner.resizeDrag(0.0f, midY);
@@ -155,15 +173,15 @@
* This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
*/
@Test
- @Ignore
public void testFreeWindowResizingTestAllEdges() throws Exception {
final Rect r = new Rect(100, 220, 700, 520);
final int midX = (r.left + r.right) / 2;
final int midY = (r.top + r.bottom) / 2;
+ mDimBounds.set(r);
// Drag upper left.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
mPositioner.resizeDrag(0.0f, 0.0f);
assertTrue(r.left != mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -171,8 +189,8 @@
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag upper.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
mPositioner.resizeDrag(0.0f, 0.0f);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -180,8 +198,8 @@
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag upper right.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
mPositioner.resizeDrag(r.right + 100, 0.0f);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertTrue(r.right != mPositioner.getWindowDragBounds().right);
@@ -189,8 +207,8 @@
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag right.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY);
mPositioner.resizeDrag(r.right + 100, 0.0f);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertTrue(r.right != mPositioner.getWindowDragBounds().right);
@@ -198,9 +216,9 @@
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag bottom right.
- mPositioner.startDrag(true /*resizing*/,
+ mPositioner.startDrag(mWindow, true /*resizing*/,
false /*preserveOrientation*/,
- r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y, r);
+ r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertTrue(r.right != mPositioner.getWindowDragBounds().right);
@@ -208,8 +226,8 @@
assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
// Drag bottom.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y);
mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -217,8 +235,8 @@
assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
// Drag bottom left.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
mPositioner.resizeDrag(0.0f, r.bottom + 100);
assertTrue(r.left != mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -226,8 +244,8 @@
assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
// Drag left.
- mPositioner.startDrag(true /*resizing*/,
- false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX);
mPositioner.resizeDrag(0.0f, r.bottom + 100);
assertTrue(r.left != mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -240,12 +258,12 @@
* right things upon resizing when dragged from the top left corner.
*/
@Test
- @Ignore
public void testLandscapePreservedWindowResizingDragTopLeft() throws Exception {
final Rect r = new Rect(100, 220, 700, 520);
+ mDimBounds.set(r);
- mPositioner.startDrag(true /*resizing*/,
- true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
assertBoundsEquals(r, mPositioner.getWindowDragBounds());
// Drag to a good landscape size.
@@ -278,13 +296,13 @@
* right things upon resizing when dragged from the left corner.
*/
@Test
- @Ignore
public void testLandscapePreservedWindowResizingDragLeft() throws Exception {
final Rect r = new Rect(100, 220, 700, 520);
final int midY = (r.top + r.bottom) / 2;
+ mDimBounds.set(r);
- mPositioner.startDrag(true /*resizing*/,
- true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
// Drag to the left.
mPositioner.resizeDrag(0.0f, midY);
@@ -319,13 +337,13 @@
* right things upon resizing when dragged from the top corner.
*/
@Test
- @Ignore
public void testLandscapePreservedWindowResizingDragTop() throws Exception {
final Rect r = new Rect(100, 220, 700, 520);
final int midX = (r.left + r.right) / 2;
+ mDimBounds.set(r);
- mPositioner.startDrag(true /*resizing*/,
- true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
// Drag to the left (no change).
mPositioner.resizeDrag(0.0f, r.top);
@@ -356,12 +374,12 @@
* right things upon resizing when dragged from the top left corner.
*/
@Test
- @Ignore
public void testPortraitPreservedWindowResizingDragTopLeft() throws Exception {
final Rect r = new Rect(330, 100, 630, 600);
+ mDimBounds.set(r);
- mPositioner.startDrag(true /*resizing*/,
- true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
assertBoundsEquals(r, mPositioner.getWindowDragBounds());
// Drag to a good landscape size.
@@ -371,8 +389,8 @@
mPositioner.getWindowDragBounds());
// Drag to a good portrait size.
- mPositioner.resizeDrag(500.0f, 0.0f);
- assertBoundsEquals(new Rect(500 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
+ mPositioner.resizeDrag(400.0f, 0.0f);
+ assertBoundsEquals(new Rect(400 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a too small size for the height and the the width shrinking.
@@ -389,13 +407,13 @@
* right things upon resizing when dragged from the left corner.
*/
@Test
- @Ignore
public void testPortraitPreservedWindowResizingDragLeft() throws Exception {
final Rect r = new Rect(330, 100, 630, 600);
final int midY = (r.top + r.bottom) / 2;
+ mDimBounds.set(r);
- mPositioner.startDrag(true /*resizing*/,
- true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
// Drag to the left.
mPositioner.resizeDrag(0.0f, midY);
@@ -432,13 +450,13 @@
* right things upon resizing when dragged from the top corner.
*/
@Test
- @Ignore
public void testPortraitPreservedWindowResizingDragTop() throws Exception {
final Rect r = new Rect(330, 100, 630, 600);
final int midX = (r.left + r.right) / 2;
+ mDimBounds.set(r);
- mPositioner.startDrag(true /*resizing*/,
- true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y, r);
+ mPositioner.startDrag(mWindow, true /*resizing*/,
+ true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
// Drag to the left (no change).
mPositioner.resizeDrag(0.0f, r.top);
@@ -472,9 +490,9 @@
+ ") " + Log.getStackTraceString(new Throwable()));
}
}
- assertEquals(expected.left, actual.left);
- assertEquals(expected.right, actual.right);
- assertEquals(expected.top, actual.top);
- assertEquals(expected.bottom, actual.bottom);
+ assertEquals("left", expected.left, actual.left);
+ assertEquals("right", expected.right, actual.right);
+ assertEquals("top", expected.top, actual.top);
+ assertEquals("bottom", expected.bottom, actual.bottom);
}
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 4334d3a..3138180 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -213,6 +213,17 @@
/**
* Notify the framework that the device is disconnected from the IMS network.
+ * <p>
+ * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo)}, you should ensure that any
+ * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent
+ * to the framework. For example,
+ * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}
+ * and
+ * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}
+ * may be set to unavailable to ensure the framework knows these services are no longer
+ * available due to de-registration. If you do not report capability changes impacted by
+ * de-registration, the framework will not know which features are no longer available as a
+ * result.
*
* @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
*/
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 61dbcc3..4c68c8b 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -9,9 +9,10 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
# frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 6ce66f0..4a6fe49 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -184,7 +184,8 @@
if (null != launchDirectory && !launchDirectory.isEmpty()) {
launchRootDir = new File(launchDirectory);
if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
- throw new IOException("Unable to create the destination directory");
+ throw new IOException("Unable to create the destination directory "
+ + launchRootDir + ". Try disabling selinux.");
}
}
@@ -192,7 +193,8 @@
File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
- throw new IOException("Unable to create the lauch file sub directory");
+ throw new IOException("Unable to create the lauch file sub directory "
+ + launchSubDir + ". Try disabling selinux.");
}
File file = new File(launchSubDir, LAUNCH_FILE);
FileOutputStream outputStream = new FileOutputStream(file);
@@ -769,6 +771,8 @@
BufferedWriter writer =
new BufferedWriter(new OutputStreamWriter(stream))) {
String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+ // In the file, we need to escape any "$".
+ cmd = cmd.replace("$", "\\$");
writer.write(cmd);
}
launchCmd = launchFile.getAbsolutePath();
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index ed9cbab..0248e97 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -77,7 +77,7 @@
@SmallTest
public class ApfTest {
private static final int TIMEOUT_MS = 500;
- private final static int MIN_APF_VERSION = 2;
+ private static final int MIN_APF_VERSION = 2;
@Mock IpConnectivityLog mLog;
@Mock Context mContext;
@@ -90,20 +90,30 @@
}
// Expected return codes from APF interpreter.
- private final static int PASS = 1;
- private final static int DROP = 0;
+ private static final int PASS = 1;
+ private static final int DROP = 0;
// Interpreter will just accept packets without link layer headers, so pad fake packet to at
// least the minimum packet size.
- private final static int MIN_PKT_SIZE = 15;
+ private static final int MIN_PKT_SIZE = 15;
private static final ApfCapabilities MOCK_APF_CAPABILITIES =
new ApfCapabilities(2, 1700, ARPHRD_ETHER);
- private final static boolean DROP_MULTICAST = true;
- private final static boolean ALLOW_MULTICAST = false;
+ private static final boolean DROP_MULTICAST = true;
+ private static final boolean ALLOW_MULTICAST = false;
- private final static boolean DROP_802_3_FRAMES = true;
- private final static boolean ALLOW_802_3_FRAMES = false;
+ private static final boolean DROP_802_3_FRAMES = true;
+ private static final boolean ALLOW_802_3_FRAMES = false;
+
+ // Constants for opcode encoding
+ private static final byte LI_OP = (byte)(13 << 3);
+ private static final byte LDDW_OP = (byte)(22 << 3);
+ private static final byte STDW_OP = (byte)(23 << 3);
+ private static final byte SIZE0 = (byte)(0 << 1);
+ private static final byte SIZE8 = (byte)(1 << 1);
+ private static final byte SIZE16 = (byte)(2 << 1);
+ private static final byte SIZE32 = (byte)(3 << 1);
+ private static final byte R1 = 1;
private static ApfConfiguration getDefaultConfig() {
ApfFilter.ApfConfiguration config = new ApfConfiguration();
@@ -636,29 +646,28 @@
*/
@Test
public void testImmediateEncoding() throws IllegalInstructionException {
- final int LI_OPCODE = 13 << 3;
ApfGenerator gen;
// 0-byte immediate: li R0, 0
- gen = new ApfGenerator(3);
+ gen = new ApfGenerator(4);
gen.addLoadImmediate(Register.R0, 0);
- assertProgramEquals(new byte[]{LI_OPCODE | (0 << 1)}, gen.generate());
+ assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
// 1-byte immediate: li R0, 42
- gen = new ApfGenerator(3);
+ gen = new ApfGenerator(4);
gen.addLoadImmediate(Register.R0, 42);
- assertProgramEquals(new byte[]{LI_OPCODE | (1 << 1), 42}, gen.generate());
+ assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
// 2-byte immediate: li R1, 0x1234
- gen = new ApfGenerator(3);
+ gen = new ApfGenerator(4);
gen.addLoadImmediate(Register.R1, 0x1234);
- assertProgramEquals(new byte[]{LI_OPCODE | (2 << 1) | 1 , 0x12, 0x34}, gen.generate());
+ assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
// 4-byte immediate: li R0, 0x12345678
gen = new ApfGenerator(3);
gen.addLoadImmediate(Register.R0, 0x12345678);
assertProgramEquals(
- new byte[]{LI_OPCODE | (3 << 1), 0x12, 0x34, 0x56, 0x78},
+ new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
gen.generate());
}
@@ -667,28 +676,61 @@
*/
@Test
public void testNegativeImmediateEncoding() throws IllegalInstructionException {
- final int LI_OPCODE = 13 << 3;
ApfGenerator gen;
// 1-byte negative immediate: li R0, -42
gen = new ApfGenerator(3);
gen.addLoadImmediate(Register.R0, -42);
- assertProgramEquals(new byte[]{LI_OPCODE | (1 << 1), -42}, gen.generate());
+ assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
- // 2-byte negative immediate: li R1, -0x1234
+ // 2-byte negative immediate: li R1, -0x1122
gen = new ApfGenerator(3);
gen.addLoadImmediate(Register.R1, -0x1122);
- assertProgramEquals(new byte[]{LI_OPCODE | (2 << 1) | 1, (byte)0xEE, (byte)0xDE},
+ assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
gen.generate());
// 4-byte negative immediate: li R0, -0x11223344
gen = new ApfGenerator(3);
gen.addLoadImmediate(Register.R0, -0x11223344);
assertProgramEquals(
- new byte[]{LI_OPCODE | (3 << 1), (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
+ new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
gen.generate());
}
+ /**
+ * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
+ */
+ @Test
+ public void testLoadStoreDataEncoding() throws IllegalInstructionException {
+ ApfGenerator gen;
+
+ // Load data with no offset: lddw R0, [0 + r1]
+ gen = new ApfGenerator(3);
+ gen.addLoadData(Register.R0, 0);
+ assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
+
+ // Store data with 8bit negative offset: lddw r0, [-42 + r1]
+ gen = new ApfGenerator(3);
+ gen.addStoreData(Register.R0, -42);
+ assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
+
+ // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
+ gen = new ApfGenerator(3);
+ gen.addStoreData(Register.R1, -0x1122);
+ assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
+ gen.generate());
+
+ // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
+ gen = new ApfGenerator(3);
+ gen.addLoadData(Register.R1, 0xDEADBEEF);
+ assertProgramEquals(
+ new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
+ gen.generate());
+ }
+
+ /**
+ * Test that the interpreter correctly executes STDW with a negative 8bit offset
+ */
@Test
public void testApfDataWrite() throws IllegalInstructionException, Exception {
byte[] packet = new byte[MIN_PKT_SIZE];
@@ -712,12 +754,15 @@
assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
}
+ /**
+ * Test that the interpreter correctly executes LDDW with a negative 16bit offset
+ */
@Test
public void testApfDataRead() throws IllegalInstructionException, Exception {
// Program that DROPs if address 10 (-6) contains 0x87654321.
ApfGenerator gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R1, 10);
- gen.addLoadData(Register.R0, -16); // 10 + -16 = -6 (offset +10 with data_len=16)
+ gen.addLoadImmediate(Register.R1, 1000);
+ gen.addLoadData(Register.R0, -1006); // 1000 + -1006 = -6 (offset +10 with data_len=16)
gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
byte[] program = gen.generate();
byte[] packet = new byte[MIN_PKT_SIZE];
@@ -737,6 +782,11 @@
assertDataMemoryContents(DROP, program, packet, data, expected_data);
}
+ /**
+ * Test that the interpreter correctly executes LDDW followed by a STDW.
+ * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
+ * offset.
+ */
@Test
public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
ApfGenerator gen = new ApfGenerator(3);
@@ -844,7 +894,7 @@
}
private static class TestApfFilter extends ApfFilter {
- public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
+ public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
private FileDescriptor mWriteSocket;
private final long mFixedTimeMs = SystemClock.elapsedRealtime();