Merge "Import translations. DO NOT MERGE" into oc-mr1-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index cca933e..e8c56f0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -201,6 +201,7 @@
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
+ field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
field public static final java.lang.String REBOOT = "android.permission.REBOOT";
diff --git a/config/copyright-header b/config/copyright-header
new file mode 100644
index 0000000..93071cd
--- /dev/null
+++ b/config/copyright-header
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
new file mode 100755
index 0000000..d55190b
--- /dev/null
+++ b/config/generate-preloaded-classes.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+if [ "$#" -lt 2 ]; then
+ echo "Usage $0 <input classes file> <blacklist file> [extra classes files]"
+ exit 1
+fi
+echo "# Preloaded-classes filter file for phones.
+#
+# Classes in this file will be allocated into the boot image, and forcibly initialized in
+# the zygote during initialization. This is a trade-off, using virtual address space to share
+# common heap between apps.
+#
+# This file has been derived for mainline phone (and tablet) usage.
+#"
+input=$1
+blacklist=$2
+shift 2
+extra_classes_files=("$@")
+sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x
+
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
new file mode 100644
index 0000000..48cdce8
--- /dev/null
+++ b/config/preloaded-classes-blacklist
@@ -0,0 +1 @@
+placeholder
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index adb3152..1c8a376 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1006,6 +1006,11 @@
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
+ } else {
+ AutofillManager afm = getAutofillManager();
+ if (afm != null) {
+ afm.dismissUi();
+ }
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index c068e6a..2755e8e 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -18,16 +18,15 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.RemoteException;
-import android.provider.Settings;
-
-import com.android.internal.os.HandlerCaller;
import android.annotation.SdkConstant;
-import android.app.Service;import android.content.Intent;
+import android.app.Service;
+import android.content.Intent;
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.Looper;
+import android.os.RemoteException;
+import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.ViewStructure;
@@ -35,6 +34,7 @@
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
+import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
/**
@@ -280,6 +280,76 @@
* calling {@link FillResponse.Builder#setIgnoredIds(AutofillId...)} so the system does not trigger
* a new {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} when these views are
* focused.
+ *
+ * <h3>Web security</h3>
+ *
+ * <p>When handling autofill requests that represent web pages (typically
+ * view structures whose root's {@link android.app.assist.AssistStructure.ViewNode#getClassName()}
+ * is a {@link android.webkit.WebView}), the service should take the following steps to verify if
+ * the structure can be autofilled with the data associated with the app requesting it:
+ *
+ * <ol>
+ * <li>Use the {@link android.app.assist.AssistStructure.ViewNode#getWebDomain()} to get the
+ * source of the document.
+ * <li>Get the canonical domain using the
+ * <a href="https://publicsuffix.org/>Public Suffix List</a> (see example below).
+ * <li>Use <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a>
+ * to obtain the package name and certificate fingerprint of the package corresponding to
+ * the canonical domain.
+ * <li>Make sure the certificate fingerprint matches the value returned by Package Manager
+ * (see "Package verification" section above).
+ * </ol>
+ *
+ * <p>Here's an example on how to get the canonical domain using
+ * <a href="https://github.com/google/guava">Guava</a>:
+ *
+ * <pre class="prettyprint">
+ * private static String getCanonicalDomain(String domain) {
+ * InternetDomainName idn = InternetDomainName.from(domain);
+ * while (!idn.isTopPrivateDomain() && idn != null) {
+ * idn = idn.parent();
+ * }
+ * return idn == null ? null : idn.toString();
+ * }
+ * </pre>
+ *
+ * <p>If the association between the web domain and app package cannot be verified through the steps
+ * above, the service can still autofill the app, but it should warn the user about the potential
+ * data leakage first, and askfor the user to confirm. For example, the service could:
+ *
+ * <ol>
+ * <li>Create a dataset that requires
+ * {@link Dataset.Builder#setAuthentication(android.content.IntentSender) authentication} to
+ * unlock.
+ * <li>Include the web domain in the custom presentation for the
+ * {@link Dataset.Builder#setValue(AutofillId, AutofillValue, android.widget.RemoteViews)
+ * dataset value}.
+ * <li>When the user select that dataset, show a disclaimer dialog explaining that the app is
+ * requesting credentials for a web domain, but the service could not verify if the app owns
+ * that domain. If the user agrees, then the service can unlock the dataset.
+ * <li>Similarly, when adding a {@link SaveInfo} object for the request, the service should
+ * include the above disclaimer in the {@link SaveInfo.Builder#setDescription(CharSequence)}.
+ * </ol>
+ *
+ * <p>This same procedure could also be used when the autofillable data is contained inside an
+ * {@code IFRAME}, in which case the WebView generates a new autofill context when a node inside
+ * the {@code IFRAME} is focused, which the root node containing the {@code IFRAME}'s {@code src}
+ * attribute on {@link android.app.assist.AssistStructure.ViewNode#getWebDomain()}. A typical and
+ * legitimate use case for this scenario is a financial app that allows the user
+ * to login on different bank accounts. For example, a financial app {@code my_financial_app} could
+ * use a WebView that loads contents from {@code banklogin.my_financial_app.com}, which contains an
+ * {@code IFRAME} node whose {@code src} attribute is {@code login.some_bank.com}. When fulfilling
+ * that request, the service could add an
+ * {@link Dataset.Builder#setAuthentication(android.content.IntentSender) authenticated dataset}
+ * whose presentation displays "Username for some_bank.com" and
+ * "Password for some_bank.com". Then when the user taps one of these options, the service
+ * shows the disclaimer dialog explaining that selecting that option would release the
+ * {@code login.some_bank.com} credentials to the {@code my_financial_app}; if the user agrees,
+ * then the service returns an unlocked dataset with the {@code some_bank.com} credentials.
+ *
+ * <p><b>Note:</b> The autofill service could also whitelist well-known browser apps and skip the
+ * verifications above, as long as the service can verify the authenticity of the browser app by
+ * checking its signing certificate.
*/
public abstract class AutofillService extends Service {
private static final String TAG = "AutofillService";
@@ -424,7 +494,7 @@
* {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
* to notify the result of the request.
*
- * <p><b>NOTE: </b>to retrieve the actual value of the field, the service should call
+ * <p><b>Note:</b> To retrieve the actual value of the field, the service should call
* {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}; if it calls
* {@link android.app.assist.AssistStructure.ViewNode#getText()} or other methods, there is no
* guarantee such method will return the most recent value of the field.
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 287dc76..9b52934 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -106,6 +106,8 @@
if (mPayload != null) {
dest.writeInt(mPayload.length);
dest.writeByteArray(mPayload);
+ } else {
+ dest.writeInt(0);
}
}
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f548d3b..1c6275f 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -195,7 +195,8 @@
// Needed for throttling onComputeColors.
private long mLastColorInvalidation;
private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
- private Supplier<Long> mClockFunction = SystemClock::elapsedRealtime;
+ private final Supplier<Long> mClockFunction;
+ private final Handler mHandler;
DisplayManager mDisplayManager;
Display mDisplay;
@@ -362,6 +363,26 @@
}
}
};
+
+ /**
+ * Default constructor
+ */
+ public Engine() {
+ this(SystemClock::elapsedRealtime, Handler.getMain());
+ }
+
+ /**
+ * Constructor used for test purposes.
+ *
+ * @param clockFunction Supplies current times in millis.
+ * @param handler Used for posting/deferring asynchronous calls.
+ * @hide
+ */
+ @VisibleForTesting
+ public Engine(Supplier<Long> clockFunction, Handler handler) {
+ mClockFunction = clockFunction;
+ mHandler = handler;
+ }
/**
* Provides access to the surface in which this wallpaper is drawn.
@@ -563,18 +584,17 @@
*/
public void notifyColorsChanged() {
final long now = mClockFunction.get();
- final Handler mainHandler = Handler.getMain();
if (now - mLastColorInvalidation < NOTIFY_COLORS_RATE_LIMIT_MS) {
Log.w(TAG, "This call has been deferred. You should only call "
+ "notifyColorsChanged() once every "
+ (NOTIFY_COLORS_RATE_LIMIT_MS / 1000f) + " seconds.");
- if (!mainHandler.hasCallbacks(mNotifyColorsChanged)) {
- mainHandler.postDelayed(mNotifyColorsChanged, NOTIFY_COLORS_RATE_LIMIT_MS);
+ if (!mHandler.hasCallbacks(mNotifyColorsChanged)) {
+ mHandler.postDelayed(mNotifyColorsChanged, NOTIFY_COLORS_RATE_LIMIT_MS);
}
return;
}
mLastColorInvalidation = now;
- mainHandler.removeCallbacks(mNotifyColorsChanged);
+ mHandler.removeCallbacks(mNotifyColorsChanged);
try {
final WallpaperColors newColors = onComputeColors();
@@ -662,14 +682,6 @@
}
}
- /**
- * @hide
- */
- @VisibleForTesting
- public void setClockFunction(Supplier<Long> clockFunction) {
- mClockFunction = clockFunction;
- }
-
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface: destroyed");
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 29e5523..a0d9099 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1339,6 +1339,25 @@
}
/**
+ * Dismiss the Autofill UI, even if associated with other sessions.
+ *
+ * <p>Typically called when a new activity starts so it can hide the existing Save UI (if any).
+ *
+ * @hide
+ */
+ public void dismissUi() {
+ if (sVerbose) Log.v(TAG, "dismissUi()");
+
+ if (mService == null) return;
+
+ try {
+ mService.dismissUi();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* View tracking information. Once all tracked views become invisible the session is finished.
*/
private class TrackedViews {
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 627afa7..aa8e19a 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -49,4 +49,5 @@
void disableOwnedAutofillServices(int userId);
boolean isServiceSupported(int userId);
boolean isServiceEnabled(int userId, String packageName);
+ void dismissUi();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 650c7d9..049f1ef 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2725,6 +2725,18 @@
* understood by the {@link android.service.autofill.AutofillService} implementations:
*
* <ol>
+ * <li>Only the HTML nodes inside a {@code FORM} are generated.
+ * <li>The source of the HTML is set using {@link ViewStructure#setWebDomain(String)} in the
+ * node representing the WebView.
+ * <li>If a web page has multiple {@code FORM}s, only the data for the current form is
+ * represented—if the user taps a field from another form, then the current autofill
+ * context is canceled (by calling {@link android.view.autofill.AutofillManager#cancel()} and
+ * a new context is created for that {@code FORM}.
+ * <li>Similarly, if the page has {@code IFRAME} nodes, they are not initially represented in
+ * the view structure until the user taps a field from a {@code FORM} inside the
+ * {@code IFRAME}, in which case it would be treated the same way as multiple forms described
+ * above, except that the {@link ViewStructure#setWebDomain(String) web domain} of the
+ * {@code FORM} contains the {@code src} attribute from the {@code IFRAME} node.
* <li>If the Android SDK provides a similar View, then should be set with the
* fully-qualified class name of such view.
* <li>The W3C autofill field ({@code autocomplete} tag attribute) maps to
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f294b98..86c0b43 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1984,6 +1984,15 @@
android:description="@string/permdesc_setWallpaperHints"
android:protectionLevel="normal" />
+ <!-- Allow the app to read the system wallpaper image without
+ holding the READ_EXTERNAL_STORAGE permission.
+ <p>Not for use by third-party applications.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.READ_WALLPAPER_INTERNAL"
+ android:protectionLevel="signature|privileged" />
+
<!-- ============================================ -->
<!-- Permissions for changing the system clock -->
<!-- ============================================ -->
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index bc41810..8b03468 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -99,13 +99,22 @@
}
auto deviceInfo = DeviceInfo::get();
+ auto displayInfo = deviceInfo->displayInfo();
int maxTextureSize = deviceInfo->maxTextureSize();
+ // Adjust cache size based on Pixel's desnsity.
+ constexpr float PIXEL_DENSITY = 2.6;
+ const float densityRatio = displayInfo.density / PIXEL_DENSITY;
+
// TODO: Most devices are hardcoded with this configuration, does it need to be dynamic?
- mSmallCacheWidth = std::min(1024, maxTextureSize);
- mSmallCacheHeight = std::min(1024, maxTextureSize);
- mLargeCacheWidth = std::min(2048, maxTextureSize);
- mLargeCacheHeight = std::min(1024, maxTextureSize);
+ mSmallCacheWidth =
+ OffscreenBuffer::computeIdealDimension(std::min(1024, maxTextureSize) * densityRatio);
+ mSmallCacheHeight =
+ OffscreenBuffer::computeIdealDimension(std::min(1024, maxTextureSize) * densityRatio);
+ mLargeCacheWidth =
+ OffscreenBuffer::computeIdealDimension(std::min(2048, maxTextureSize) * densityRatio);
+ mLargeCacheHeight =
+ OffscreenBuffer::computeIdealDimension(std::min(1024, maxTextureSize) * densityRatio);
if (sLogFontRendererCreate) {
INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index db3274a..1f1b67e 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -121,8 +121,8 @@
<item>Use System Selection (Default)</item>
<item>SBC</item>
<item>AAC</item>
- <item>aptX</item>
- <item>aptX HD</item>
+ <item><xliff:g id="aptx">Qualcomm(R) aptX(TM) audio</xliff:g></item>
+ <item><xliff:g id="aptx_hd">Qualcomm(R) aptX(TM) HD audio</xliff:g></item>
<item>LDAC</item>
<item>Enable Optional Codecs</item>
<item>Disable Optional Codecs</item>
@@ -145,8 +145,8 @@
<item>Use System Selection (Default)</item>
<item>SBC</item>
<item>AAC</item>
- <item>aptX</item>
- <item>aptX HD</item>
+ <item><xliff:g id="aptx">Qualcomm(R) aptX(TM) audio</xliff:g></item>
+ <item><xliff:g id="aptx_hd">Qualcomm(R) aptX(TM) HD audio</xliff:g></item>
<item>LDAC</item>
<item>Enable Optional Codecs</item>
<item>Disable Optional Codecs</item>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
index 5243228..1285ed8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java
@@ -27,7 +27,7 @@
public static final String ACTION = "com.android.systemui.action.PLUGIN_NAV_BUTTON";
- public static final int VERSION = 2;
+ public static final int VERSION = 3;
/**
* Returns a view in the nav bar. If the id is set "back", "home", "recent_apps", "menu",
@@ -46,8 +46,6 @@
void setVertical(boolean vertical);
- void setCarMode(boolean carMode);
-
void setDarkIntensity(float intensity);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 669594b..bb6213b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1157,10 +1157,16 @@
}
}
+ private boolean shouldListenForFingerprintAssistant() {
+ return mAssistantVisible && mKeyguardOccluded
+ && !mUserFingerprintAuthenticated.get(getCurrentUser(), false)
+ && !mUserHasTrust.get(getCurrentUser(), false);
+ }
+
private boolean shouldListenForFingerprint() {
return (mKeyguardIsVisible || !mDeviceInteractive ||
(mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
- (mAssistantVisible && mKeyguardOccluded))
+ shouldListenForFingerprintAssistant())
&& !mSwitchingUser && !isFingerprintDisabled(getCurrentUser())
&& !mKeyguardGoingAway;
}
diff --git a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
index 9fe730a..81e4db3 100644
--- a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
@@ -33,6 +33,7 @@
private static final String TAG = "DockedStackExistsListener";
private static ArrayList<WeakReference<Consumer<Boolean>>> sCallbacks = new ArrayList<>();
+ private static boolean mLastExists;
static {
try {
@@ -73,6 +74,7 @@
private static void onDockedStackExistsChanged(boolean exists) {
+ mLastExists = exists;
synchronized (sCallbacks) {
sCallbacks.removeIf(wf -> {
Consumer<Boolean> l = wf.get();
@@ -83,6 +85,7 @@
}
public static void register(Consumer<Boolean> callback) {
+ callback.accept(mLastExists);
synchronized (sCallbacks) {
sCallbacks.add(new WeakReference<>(callback));
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 9b48320..56a3c87 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -31,7 +31,6 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -47,10 +46,8 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.tuner.TunerService;
import java.io.PrintWriter;
@@ -90,6 +87,8 @@
// The current movement bounds
private Rect mMovementBounds = new Rect();
+ // The reference inset bounds, used to determine the dismiss fraction
+ private Rect mInsetBounds = new Rect();
// The reference bounds used to calculate the normal/expanded target bounds
private Rect mNormalBounds = new Rect();
private Rect mNormalMovementBounds = new Rect();
@@ -311,6 +310,7 @@
mNormalMovementBounds = normalMovementBounds;
mExpandedMovementBounds = expandedMovementBounds;
mDisplayRotation = displayRotation;
+ mInsetBounds.set(insetBounds);
updateMovementBounds(mMenuState);
// If we have a deferred resize, apply it now
@@ -418,9 +418,12 @@
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
*/
private void updateDismissFraction() {
- if (mMenuController != null) {
+ // Skip updating the dismiss fraction when the IME is showing. This is to work around an
+ // issue where starting the menu activity for the dismiss overlay will steal the window
+ // focus, which closes the IME.
+ if (mMenuController != null && !mIsImeShowing) {
Rect bounds = mMotionHelper.getBounds();
- final float target = mMovementBounds.bottom + bounds.height();
+ final float target = mInsetBounds.bottom;
float fraction = 0f;
if (bounds.bottom > target) {
final float distance = bounds.bottom - target;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 86e93fd..1b86143 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -24,6 +24,7 @@
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
+import android.app.ActivityOptions.OnAnimationFinishedListener;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -663,7 +664,7 @@
mWaitingForTransitionStart = waitingForTransitionStart;
if (!waitingForTransitionStart && mToggleFollowingTransitionStart) {
- toggleRecents(DividerView.INVALID_RECENTS_GROW_TARGET);
+ mHandler.post(() -> toggleRecents(DividerView.INVALID_RECENTS_GROW_TARGET));
}
mToggleFollowingTransitionStart = false;
}
@@ -866,6 +867,7 @@
private Pair<ActivityOptions, AppTransitionAnimationSpecsFuture>
getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo runningTask,
Rect windowOverrideRect) {
+ final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
ArrayList<Task> tasks;
@@ -896,8 +898,11 @@
AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
specs.toArray(specsArray);
+ // For low end ram devices, wait for transition flag is reset when Recents entrance
+ // animation is complete instead of when the transition animation starts
return new Pair<>(ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- specsArray, mHandler, mResetToggleFlagListener, this), null);
+ specsArray, mHandler, isLowRamDevice ? null : mResetToggleFlagListener, this),
+ null);
} else {
// Update the destination rect
Task toTask = new Task();
@@ -916,9 +921,11 @@
toTask.key.id, thumbnail, rect));
});
+ // For low end ram devices, wait for transition flag is reset when Recents entrance
+ // animation is complete instead of when the transition animation starts
return new Pair<>(ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
- mHandler, future.getFuture(), mResetToggleFlagListener, false /* scaleUp */),
- future);
+ mHandler, future.getFuture(), isLowRamDevice ? null : mResetToggleFlagListener,
+ false /* scaleUp */), future);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 127822a..b2675d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -140,8 +140,10 @@
mHandler.postDelayed(mStartScreenPinningRunnable, 350);
}
- // Reset the state where we are waiting for the transition to start
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ if (!Recents.getConfiguration().isLowRamDevice) {
+ // Reset the state where we are waiting for the transition to start
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ }
}
};
} else {
@@ -163,8 +165,10 @@
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
stackView.cancelAllTaskViewAnimations();
- // Reset the state where we are waiting for the transition to start
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ if (!Recents.getConfiguration().isLowRamDevice) {
+ // Reset the state where we are waiting for the transition to start
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ }
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 6e57044..81bf6af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -34,6 +34,8 @@
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -241,6 +243,7 @@
return;
}
+ final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
int taskViewEnterFromAppDuration = res.getInteger(
R.integer.recents_task_enter_from_app_duration);
int taskViewEnterFromAffiliatedAppDuration = res.getInteger(
@@ -248,6 +251,13 @@
int dockGestureAnimDuration = appRes.getInteger(
R.integer.long_press_dock_anim_duration);
+ // Since low ram devices have an animation when entering app -> recents, do not allow
+ // toggle until the animation is complete
+ if (launchState.launchedFromApp && !launchState.launchedViaDockGesture && isLowRamDevice) {
+ postAnimationTrigger.addLastDecrementRunnable(() -> EventBus.getDefault()
+ .send(new SetWaitingForTransitionStartEvent(false)));
+ }
+
// Create enter animations for each of the views from front to back
List<TaskView> taskViews = mStackView.getTaskViews();
int taskViewCount = taskViews.size();
@@ -296,7 +306,7 @@
AnimationProps taskAnimation = new AnimationProps()
.setInterpolator(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_INTERPOLATOR)
.setListener(postAnimationTrigger.decrementOnAnimationEnd());
- if (Recents.getConfiguration().isLowRamDevice) {
+ if (isLowRamDevice) {
taskAnimation.setInterpolator(AnimationProps.BOUNDS,
Interpolators.FAST_OUT_SLOW_IN)
.setDuration(AnimationProps.BOUNDS, 150)
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 2bc2665..a83e659 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -174,16 +174,6 @@
mCurrentView = currentView.findViewById(mId);
}
- public void setCarMode(boolean carMode) {
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
- final View view = mViews.get(i);
- if (view instanceof ButtonInterface) {
- ((ButtonInterface) view).setCarMode(carMode);
- }
- }
- }
-
public void setVertical(boolean vertical) {
mVertical = vertical;
final int N = mViews.size();
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 57c8827..9a7039a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -683,8 +683,6 @@
if (isCarMode != mInCarMode) {
mInCarMode = isCarMode;
- getHomeButton().setCarMode(isCarMode);
-
if (ALTERNATE_CAR_MODE_UI) {
mUseCarModeUi = isCarMode;
uiCarModeChanged = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 65bfb49..0df3321 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5153,6 +5153,14 @@
recomputeDisableFlags(true /* animate */);
}
+ public void cancelCurrentTouch() {
+ if (mNotificationPanel.isTracking()) {
+ mStatusBarWindow.cancelCurrentTouch();
+ if (mState == StatusBarState.SHADE) {
+ animateCollapsePanels();
+ }
+ }
+ }
WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 65bfabd..0501771 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -304,11 +304,6 @@
public void setVertical(boolean vertical) {
//no op
}
-
- @Override
- public void setCarMode(boolean carMode) {
- // no op
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenRadioLayout.java b/packages/SystemUI/src/com/android/systemui/volume/ZenRadioLayout.java
index 5dbcd8a..360907b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenRadioLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenRadioLayout.java
@@ -46,9 +46,16 @@
throw new IllegalStateException("Expected matching children");
}
boolean hasChanges = false;
+ View lastView = null;
for (int i = 0; i < size; i++) {
View radio = radioGroup.getChildAt(i);
View content = radioContent.getChildAt(i);
+ if (lastView != null) {
+ radio.setAccessibilityTraversalAfter(lastView.getId());
+ }
+ View contentClick = findFirstClickable(content);
+ if (contentClick != null) contentClick.setAccessibilityTraversalAfter(radio.getId());
+ lastView = findLastClickable(content);
if (radio.getLayoutParams().height != content.getMeasuredHeight()) {
hasChanges = true;
radio.getLayoutParams().height = content.getMeasuredHeight();
@@ -59,4 +66,28 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
+
+ private View findFirstClickable(View content) {
+ if (content.isClickable()) return content;
+ if (content instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) content;
+ for (int i = 0; i < group.getChildCount(); i++) {
+ View v = findFirstClickable(group.getChildAt(i));
+ if (v != null) return v;
+ }
+ }
+ return null;
+ }
+
+ private View findLastClickable(View content) {
+ if (content.isClickable()) return content;
+ if (content instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) content;
+ for (int i = group.getChildCount() - 1; i >= 0; i--) {
+ View v = findLastClickable(group.getChildAt(i));
+ if (v != null) return v;
+ }
+ }
+ return null;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index d0f0bfd..6417eb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -17,6 +17,7 @@
package com.android.systemui.colorextraction;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
@@ -25,7 +26,6 @@
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.types.Tonal;
import com.android.systemui.SysuiTestCase;
import org.junit.Test;
@@ -48,18 +48,21 @@
@Test
public void getColors_usesGreyIfWallpaperNotVisible() {
- SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(),
- new Tonal(getContext()), false);
+ ColorExtractor.GradientColors colors = new ColorExtractor.GradientColors();
+ colors.setMainColor(Color.RED);
+ colors.setSecondaryColor(Color.RED);
+
+ SysuiColorExtractor extractor = getTestableExtractor(colors);
simulateEvent(extractor);
extractor.setWallpaperVisible(false);
ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
- for (int which : sWhich) {
- for (int type : sTypes) {
- assertEquals("Not using fallback!", extractor.getColors(which, type),
- fallbackColors);
- }
+ for (int type : sTypes) {
+ assertEquals("Not using fallback!",
+ extractor.getColors(WallpaperManager.FLAG_SYSTEM, type), fallbackColors);
+ assertNotEquals("Wallpaper visibility event should not affect lock wallpaper.",
+ extractor.getColors(WallpaperManager.FLAG_LOCK, type), fallbackColors);
}
}
@@ -69,13 +72,7 @@
colors.setMainColor(Color.RED);
colors.setSecondaryColor(Color.RED);
- SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(),
- (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
- outGradientColorsExtraDark) -> {
- outGradientColorsNormal.set(colors);
- outGradientColorsDark.set(colors);
- outGradientColorsExtraDark.set(colors);
- }, false);
+ SysuiColorExtractor extractor = getTestableExtractor(colors);
simulateEvent(extractor);
extractor.setWallpaperVisible(true);
@@ -87,6 +84,16 @@
}
}
+ private SysuiColorExtractor getTestableExtractor(ColorExtractor.GradientColors colors) {
+ return new SysuiColorExtractor(getContext(),
+ (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
+ outGradientColorsExtraDark) -> {
+ outGradientColorsNormal.set(colors);
+ outGradientColorsDark.set(colors);
+ outGradientColorsExtraDark.set(colors);
+ }, false);
+ }
+
private void simulateEvent(SysuiColorExtractor extractor) {
// Let's fake a color event
extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN), null, null, 0),
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 71f699c..e854079 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -655,6 +655,19 @@
}
@Override
+ public void dismissUi() {
+ final UserHandle user = getCallingUserHandle();
+
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(
+ user.getIdentifier());
+ if (service != null) {
+ service.dismissUi();
+ }
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 751c054..841b1a5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -41,7 +41,6 @@
import android.os.Looper;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
@@ -635,6 +634,12 @@
}
}
+ void dismissUi() {
+ if (sVerbose) Slog.v(TAG, "dismissUi()");
+
+ mUi.hideAll(null);
+ }
+
private void sendStateToClients(boolean resetClient) {
final RemoteCallbackList<IAutoFillManagerClient> clients;
final int userClientCount;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 5e25dfa..2a2797c 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -290,7 +290,7 @@
}
private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
- CharSequence message) {
+ @Nullable CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
@@ -298,6 +298,16 @@
});
}
+ private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellationSignal) {
+ mHandler.getHandler().post(() -> {
+ try {
+ cancellationSignal.cancel();
+ } catch (RemoteException e) {
+ Slog.w(LOG_TAG, "Error calling cancellation signal: " + e);
+ }
+ });
+ }
+
private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
@@ -307,7 +317,7 @@
}
private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest,
- CharSequence message) {
+ @Nullable CharSequence message) {
mHandler.getHandler().post(() -> {
if (handleResponseCallbackCommon(pendingRequest)) {
mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName());
@@ -432,7 +442,7 @@
if (remoteService != null) {
Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out after "
+ TIMEOUT_REMOTE_REQUEST_MILLIS + " ms");
- fail(remoteService);
+ onTimeout(remoteService);
}
};
mServiceHandler.postAtTime(mTimeoutTrigger,
@@ -485,7 +495,7 @@
* Called by the self-destructure timeout when the AutofilllService didn't reply to the
* request on time.
*/
- abstract void fail(RemoteFillService remoteService);
+ abstract void onTimeout(RemoteFillService remoteService);
/**
* @return whether this request leads to a final state where no
@@ -549,7 +559,10 @@
}
@Override
- void fail(RemoteFillService remoteService) {
+ void onTimeout(RemoteFillService remoteService) {
+ // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
+ // handled by the service, which could block.
+ remoteService.dispatchOnFillTimeout(mCancellation);
remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
}
@@ -617,7 +630,7 @@
}
@Override
- void fail(RemoteFillService remoteService) {
+ void onTimeout(RemoteFillService remoteService) {
remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
}
@@ -630,7 +643,7 @@
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on save request", e);
- remoteService.dispatchOnFillRequestFailure(PendingSaveRequest.this, null);
+ remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7a0c706..8de13bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5470,6 +5470,10 @@
configureHdmiPlugIntent(intent, state);
}
+ if (intent.getAction() == null) {
+ return;
+ }
+
intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
@@ -5543,9 +5547,7 @@
}
}
}
- if (device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
- sendDeviceConnectionIntent(device, state, address, deviceName);
- }
+ sendDeviceConnectionIntent(device, state, address, deviceName);
updateAudioRoutes(device, state);
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 8087813..beaddb4 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -212,12 +212,25 @@
}
}
- protected void onSettingRestored(String element, String value, int userId) {
+ protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
if (!mUseXml) {
Slog.d(TAG, "Restored managed service setting: " + element);
if (mConfig.secureSettingName.equals(element) ||
(mConfig.secondarySettingName != null
&& mConfig.secondarySettingName.equals(element))) {
+ if (backupSdkInt < Build.VERSION_CODES.O) {
+ // automatic system grants were added in O, so append the approved apps
+ // rather than wiping out the setting
+ String currentSetting =
+ getApproved(userId, mConfig.secureSettingName.equals(element));
+ if (!TextUtils.isEmpty(currentSetting)) {
+ if (!TextUtils.isEmpty(value)) {
+ value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
+ } else {
+ value = currentSetting;
+ }
+ }
+ }
Settings.Secure.putStringForUser(
mContext.getContentResolver(), element, value, userId);
loadAllowedComponentsFromSettings();
@@ -370,6 +383,13 @@
}
}
+ protected String getApproved(int userId, boolean primary) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
+ return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ }
+
protected List<ComponentName> getAllowedComponents(int userId) {
final List<ComponentName> allowedComponents = new ArrayList<>();
final ArrayMap<Boolean, ArraySet<String>> allowedByType =
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6aa83b3..28acd9a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -817,8 +817,10 @@
String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
int restoredFromSdkInt = intent.getIntExtra(
Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
- mListeners.onSettingRestored(element, newValue, getSendingUserId());
- mConditionProviders.onSettingRestored(element, newValue, getSendingUserId());
+ mListeners.onSettingRestored(
+ element, newValue, restoredFromSdkInt, getSendingUserId());
+ mConditionProviders.onSettingRestored(
+ element, newValue, restoredFromSdkInt, getSendingUserId());
} catch (Exception e) {
Slog.wtf(TAG, "Cannot restore managed services from settings", e);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 2fad7b1..f6f5341 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1606,8 +1606,12 @@
@Override
public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
final int which, Bundle outParams, int wallpaperUserId) {
- enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
- callingPkg, Binder.getCallingUid(), "read wallpaper");
+ final int hasPrivilege = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.READ_WALLPAPER_INTERNAL);
+ if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
+ enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ callingPkg, Binder.getCallingUid(), "read wallpaper");
+ }
wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
diff --git a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
index 3603f2f..b0eaf14 100644
--- a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
+++ b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
@@ -26,9 +26,8 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
@@ -73,9 +72,8 @@
super(s, name, w, h, format, flags, windowType, ownerUid);
// We should only show background behind app windows that are letterboxed in a task.
- if (!windowSurfaceController.mAnimator.mWin.isLetterboxedAppWindow()
- || windowType < FIRST_APPLICATION_WINDOW
- || windowType > LAST_APPLICATION_WINDOW) {
+ if ((windowType != TYPE_BASE_APPLICATION && windowType != TYPE_APPLICATION_STARTING)
+ || !windowSurfaceController.mAnimator.mWin.isLetterboxedAppWindow()) {
return;
}
mWindowSurfaceController = windowSurfaceController;
diff --git a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java
index bd65f57..8242149 100644
--- a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java
@@ -38,6 +38,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
+import android.os.Build;
import android.os.IBinder;
import android.os.IInterface;
import android.os.UserHandle;
@@ -146,19 +147,86 @@
service.onSettingRestored(
service.getConfig().secureSettingName,
mExpectedPrimary.get(approvalLevel).get(userId),
- userId);
+ Build.VERSION_CODES.O, userId);
}
verifyExpectedApprovedEntries(service, true);
for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
service.onSettingRestored(service.getConfig().secondarySettingName,
- mExpectedSecondary.get(approvalLevel).get(userId), userId);
+ mExpectedSecondary.get(approvalLevel).get(userId), Build.VERSION_CODES.O,
+ userId);
}
verifyExpectedApprovedEntries(service);
}
}
@Test
+ public void testBackupAndRestore_migration_preO() throws Exception {
+ ArrayMap backupPrimaryPackages = new ArrayMap<>();
+ backupPrimaryPackages.put(0, "backup.0:backup:0a");
+ backupPrimaryPackages.put(10, "10.backup");
+ backupPrimaryPackages.put(11, "eleven");
+ backupPrimaryPackages.put(12, "");
+ ArrayMap backupPrimaryComponentNames = new ArrayMap<>();
+ backupPrimaryComponentNames.put(0, "backup.first/whatever:a/b");
+ backupPrimaryComponentNames.put(10, "again/M1");
+ backupPrimaryComponentNames.put(11, "orange/youglad:itisnot/banana");
+ backupPrimaryComponentNames.put(12, "");
+ ArrayMap<Integer, ArrayMap<Integer, String>> backupPrimary = new ArrayMap<>();
+ backupPrimary.put(APPROVAL_BY_PACKAGE, backupPrimaryPackages);
+ backupPrimary.put(APPROVAL_BY_COMPONENT, backupPrimaryComponentNames);
+
+ ArrayMap backupSecondaryComponentNames = new ArrayMap<>();
+ backupSecondaryComponentNames.put(0, "secondary.1/component.Name");
+ backupSecondaryComponentNames.put(10,
+ "this.is.another.package.backup/with.Component:component.backup/2");
+ ArrayMap backupSecondaryPackages = new ArrayMap<>();
+ backupSecondaryPackages.put(0, "");
+ backupSecondaryPackages.put(10,
+ "this.is.another.package.backup:package.backup");
+ ArrayMap<Integer, ArrayMap<Integer, String>> backupSecondary = new ArrayMap<>();
+ backupSecondary.put(APPROVAL_BY_PACKAGE, backupSecondaryPackages);
+ backupSecondary.put(APPROVAL_BY_COMPONENT, backupSecondaryComponentNames);
+
+ for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm, approvalLevel);
+
+ // not an expected flow but a way to get data into the settings
+ for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
+ service.onSettingRestored(
+ service.getConfig().secureSettingName,
+ mExpectedPrimary.get(approvalLevel).get(userId),
+ Build.VERSION_CODES.O, userId);
+ }
+
+ for (int userId : mExpectedSecondary.get(approvalLevel).keySet()) {
+ service.onSettingRestored(service.getConfig().secondarySettingName,
+ mExpectedSecondary.get(approvalLevel).get(userId), Build.VERSION_CODES.O,
+ userId);
+ }
+
+ // actual test
+ for (int userId : backupPrimary.get(approvalLevel).keySet()) {
+ service.onSettingRestored(
+ service.getConfig().secureSettingName,
+ backupPrimary.get(approvalLevel).get(userId),
+ Build.VERSION_CODES.N_MR1, userId);
+ }
+ verifyExpectedApprovedEntries(service, true);
+
+ for (int userId : backupSecondary.get(approvalLevel).keySet()) {
+ service.onSettingRestored(service.getConfig().secondarySettingName,
+ backupSecondary.get(approvalLevel).get(userId),
+ Build.VERSION_CODES.N_MR1, userId);
+ }
+ verifyExpectedApprovedEntries(service);
+ verifyExpectedApprovedEntries(service, backupPrimary.get(approvalLevel));
+ verifyExpectedApprovedEntries(service, backupSecondary.get(approvalLevel));
+ }
+ }
+
+ @Test
public void testReadXml_migrationFromSettings() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -619,25 +687,22 @@
ArrayMap<Integer, String> verifyMap = primary
? mExpectedPrimary.get(service.mApprovalLevel)
: mExpectedSecondary.get(service.mApprovalLevel);
+ verifyExpectedApprovedEntries(service, verifyMap);
+ }
+
+ private void verifyExpectedApprovedEntries(ManagedServices service,
+ ArrayMap<Integer, String> verifyMap) {
for (int userId : verifyMap.keySet()) {
for (String verifyValue : verifyMap.get(userId).split(":")) {
if (!TextUtils.isEmpty(verifyValue)) {
assertTrue("service type " + service.mApprovalLevel + ":"
- + verifyValue + " is not allowed for user " + userId,
+ + verifyValue + " is not allowed for user " + userId,
service.isPackageOrComponentAllowed(verifyValue, userId));
}
}
}
}
- private boolean isPackage(String packageOrComponent) {
- final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
- if (component != null) {
- return false;
- }
- return true;
- }
-
private void writeExpectedValuesToSettings(int approvalLevel) {
for (int userId : mExpectedPrimary.get(approvalLevel).keySet()) {
Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING,
diff --git a/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java b/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java
index 0d29e89..9c010a0 100644
--- a/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java
@@ -17,10 +17,14 @@
package com.android.server.wallpaper;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.app.WallpaperColors;
+import android.os.Handler;
+import android.os.Message;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
+import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -28,18 +32,31 @@
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
+import java.util.function.Supplier;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WallpaperServiceTests {
+ @UiThreadTest
@Test
public void testNotifyColorsChanged_rateLimit() throws Exception {
+ long[] clockOffset = {0};
+ boolean[] postDelayed = {false};
+ Supplier<Long> clockFunction = () -> SystemClock.elapsedRealtime() + clockOffset[0];
+ Handler handler = new Handler() {
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ postDelayed[0] = true;
+ return super.sendMessageAtTime(msg, uptimeMillis);
+ }
+ };
+
CountDownLatch eventCountdown = new CountDownLatch(2);
WallpaperService service = new WallpaperService() {
@Override
public Engine onCreateEngine() {
- return new WallpaperService.Engine() {
+ return new WallpaperService.Engine(clockFunction, handler) {
@Override
public WallpaperColors onComputeColors() {
eventCountdown.countDown();
@@ -59,8 +76,11 @@
engine.notifyColorsChanged();
assertEquals("OnComputeColors should have been throttled.",
1, eventCountdown.getCount());
- // Called after being deferred.
- engine.setClockFunction(() -> SystemClock.elapsedRealtime() + 1500);
+ // Should have been posted to the handler.
+ assertTrue("Event should have been delayed", postDelayed[0]);
+
+ // Called again after being deferred.
+ clockOffset[0] = 1500;
engine.notifyColorsChanged();
assertEquals("OnComputeColors should have been deferred.",
0, eventCountdown.getCount());
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 23db6ac..3a34d8f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1363,6 +1363,16 @@
"network_notification_delay_int";
/**
+ * Time delay (in ms) after which we show the notification for emergency calls,
+ * while the device is registered over WFC. Default value is -1, which indicates
+ * that this notification is not pertinent for a particular carrier. We've added a delay
+ * to prevent false positives.
+ * @hide
+ */
+ public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT =
+ "emergency_notification_delay_int";
+
+ /**
* When {@code true}, the carrier allows the user of the
* {@link TelephonyManager#sendUssdRequest(String, TelephonyManager.UssdResponseCallback,
* Handler)} API to perform USSD requests. {@code True} by default.
@@ -1788,6 +1798,7 @@
sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, false);
sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
+ sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1);
sDefaults.putBoolean(KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);