Merge "Fix issue #62390590: SecurityException in JobIntentService$..." into oc-dev
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e686a89..ee89ca8 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1469,24 +1469,21 @@
if (!mSelfPulse) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.addOneShotCommitCallback(this);
+ getAnimationHandler().addOneShotCommitCallback(this);
}
private void removeAnimationCallback() {
if (!mSelfPulse) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.removeCallback(this);
+ getAnimationHandler().removeCallback(this);
}
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
- AnimationHandler handler = AnimationHandler.getInstance();
- handler.addAnimationFrameCallback(this, delay);
+ getAnimationHandler().addAnimationFrameCallback(this, delay);
}
/**
@@ -1643,4 +1640,12 @@
public void setAllowRunningAsynchronously(boolean mayRunAsync) {
// It is up to subclasses to support this, if they can.
}
+
+ /**
+ * @return The {@link AnimationHandler} that will be used to schedule updates for this animator.
+ * @hide
+ */
+ public AnimationHandler getAnimationHandler() {
+ return AnimationHandler.getInstance();
+ }
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 9d46da1..64e464c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -44,6 +44,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
@@ -1376,6 +1377,12 @@
* android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
* {@link ParcelFileDescriptor#createReliablePipe()}, or
* {@link ParcelFileDescriptor#createReliableSocketPair()}.
+ * <p>
+ * If you need to return a large file that isn't backed by a real file on
+ * disk, such as a file on a network share or cloud storage service,
+ * consider using
+ * {@link StorageManager#openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler)}
+ * which will let you to stream the content on-demand.
*
* <p class="note">For use in Intents, you will want to implement {@link #getType}
* to return the appropriate MIME type for the data returned here with
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
index c66a3a4..8296b7a 100644
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
@@ -15,13 +15,13 @@
*/
package android.hardware.camera2.dispatch;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.hardware.camera2.utils.UncheckedThrow;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
-import static com.android.internal.util.Preconditions.*;
-
/**
* Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time).
*
@@ -31,6 +31,7 @@
private final Dispatchable<T> mTarget;
private final Class<T> mTargetClass;
+ private final Method[] mTargetClassMethods;
private final ConcurrentHashMap<String, Method> mMethods =
new ConcurrentHashMap<>();
@@ -42,6 +43,7 @@
*/
public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) {
mTargetClass = targetClass;
+ mTargetClassMethods = targetClass.getMethods();
mTarget = target;
}
@@ -68,7 +70,7 @@
Method targetMethod = mMethods.get(methodName);
if (targetMethod == null) {
- for (Method method : mTargetClass.getMethods()) {
+ for (Method method : mTargetClassMethods) {
// TODO future: match types of params if possible
if (method.getName().equals(methodName) &&
(params.length == method.getParameterTypes().length) ) {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5046735..f42edcd 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -29,6 +29,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.WorkerThread;
+import android.app.Activity;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
@@ -159,6 +160,12 @@
* If the sending application has a specific storage device or allocation
* size in mind, they can optionally define {@link #EXTRA_UUID} or
* {@link #EXTRA_REQUESTED_BYTES}, respectively.
+ * <p>
+ * This intent should be launched using
+ * {@link Activity#startActivityForResult(Intent, int)} so that the user
+ * knows which app is requesting the storage space. The returned result will
+ * be {@link Activity#RESULT_OK} if the requested space was made available,
+ * or {@link Activity#RESULT_CANCELED} otherwise.
*/
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
@@ -1467,15 +1474,26 @@
}
/**
- * Opens seekable ParcelFileDescriptor that routes file operation requests to
- * ProxyFileDescriptorCallback.
+ * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
+ * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
+ * <p>
+ * This can be useful when you want to provide quick access to a large file
+ * that isn't backed by a real file on disk, such as a file on a network
+ * share, cloud storage service, etc. As an example, you could respond to a
+ * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
+ * request by returning a {@link ParcelFileDescriptor} created with this
+ * method, and then stream the content on-demand as requested.
+ * <p>
+ * Another useful example might be where you have an encrypted file that
+ * you're willing to decrypt on-demand, but where you want to avoid
+ * persisting the cleartext version.
*
* @param mode The desired access mode, must be one of
- * {@link ParcelFileDescriptor#MODE_READ_ONLY},
- * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
- * {@link ParcelFileDescriptor#MODE_READ_WRITE}
- * @param callback Callback to process file operation requests issued on returned file
- * descriptor.
+ * {@link ParcelFileDescriptor#MODE_READ_ONLY},
+ * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
+ * {@link ParcelFileDescriptor#MODE_READ_WRITE}
+ * @param callback Callback to process file operation requests issued on
+ * returned file descriptor.
* @param handler Handler that invokes callback methods.
* @return Seekable ParcelFileDescriptor.
* @throws IOException
@@ -1487,7 +1505,6 @@
return openProxyFileDescriptor(mode, callback, handler, null);
}
-
/** {@hide} */
@VisibleForTesting
public int getProxyFileDescriptorMountPointId() {
@@ -1660,6 +1677,10 @@
* persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
* {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
* involve the user in freeing up disk space.
+ * <p>
+ * If you're progressively allocating an unbounded amount of storage space
+ * (such as when recording a video) you should avoid calling this method
+ * more than once every 30 seconds.
* <p class="note">
* Note: if your app uses the {@code android:sharedUserId} manifest feature,
* then allocatable space for all packages in your shared UID is tracked
@@ -1677,6 +1698,7 @@
* @throws IOException when the storage device isn't present, or when it
* doesn't support allocating space.
*/
+ @WorkerThread
public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
throws IOException {
return getAllocatableBytes(storageUuid, 0);
@@ -1684,6 +1706,7 @@
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public long getAllocatableBytes(@NonNull UUID storageUuid,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1699,6 +1722,7 @@
/** @removed */
@Deprecated
+ @WorkerThread
@SuppressLint("Doclava125")
public long getAllocatableBytes(@NonNull File path,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1717,6 +1741,10 @@
* subject to race conditions. If possible, consider using
* {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee
* that bytes are allocated to an opened file.
+ * <p>
+ * If you're progressively allocating an unbounded amount of storage space
+ * (such as when recording a video) you should avoid calling this method
+ * more than once every 60 seconds.
*
* @param storageUuid the UUID of the storage volume where you'd like to
* allocate disk space. The UUID for a specific path can be
@@ -1727,6 +1755,7 @@
* trouble allocating the requested space.
* @see #getAllocatableBytes(UUID, int)
*/
+ @WorkerThread
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
throws IOException {
allocateBytes(storageUuid, bytes, 0);
@@ -1734,6 +1763,7 @@
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1748,6 +1778,7 @@
/** @removed */
@Deprecated
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(@NonNull File path, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1766,6 +1797,10 @@
* otherwise it will throw if fast allocation is not possible. Fast
* allocation is typically only supported in private app data directories,
* and on shared/external storage devices which are emulated.
+ * <p>
+ * If you're progressively allocating an unbounded amount of storage space
+ * (such as when recording a video) you should avoid calling this method
+ * more than once every 60 seconds.
*
* @param fd the open file that you'd like to allocate disk space for.
* @param bytes the number of bytes to allocate. This is the desired final
@@ -1779,12 +1814,14 @@
* @see #getAllocatableBytes(UUID, int)
* @see Environment#isExternalStorageEmulated(File)
*/
+ @WorkerThread
public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
allocateBytes(fd, bytes, 0);
}
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index bc96e43..fcf18eb 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -327,17 +327,6 @@
}
/**
- * @deprecated Use {@link #setClientState(Bundle)} instead.
- * @hide
- */
- @Deprecated
- public Builder setExtras(@Nullable Bundle extras) {
- throwIfDestroyed();
- mCLientState = extras;
- return this;
- }
-
- /**
* Sets a {@link Bundle state} that will be passed to subsequent APIs that
* manipulate this response. For example, they are passed to subsequent
* calls to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ef78559..679a9cd 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1196,6 +1196,12 @@
mBackgroundControl.deferTransactionUntil(handle, frame);
}
+ @Override
+ public void deferTransactionUntil(Surface barrier, long frame) {
+ super.deferTransactionUntil(barrier, frame);
+ mBackgroundControl.deferTransactionUntil(barrier, frame);
+ }
+
void updateBackgroundVisibility() {
if (mOpaque && mVisible) {
mBackgroundControl.show();
diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
new file mode 100644
index 0000000..931eb99
--- /dev/null
+++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.graphics;
+
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
+import android.view.Choreographer;
+
+/**
+ * Provider of timing pulse that uses SurfaceFlinger Vsync Choreographer for frame callbacks.
+ *
+ * @hide
+ */
+public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider {
+
+ private final Choreographer mChoreographer = Choreographer.getSfInstance();
+
+ @Override
+ public void postFrameCallback(Choreographer.FrameCallback callback) {
+ mChoreographer.postFrameCallback(callback);
+ }
+
+ @Override
+ public void postCommitCallback(Runnable runnable) {
+ mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
+ }
+
+ @Override
+ public long getFrameTime() {
+ return mChoreographer.getFrameTime();
+ }
+
+ @Override
+ public long getFrameDelay() {
+ return Choreographer.getFrameDelay();
+ }
+
+ @Override
+ public void setFrameDelay(long delay) {
+ Choreographer.setFrameDelay(delay);
+ }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index d834e63..52357ac 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -25,7 +25,6 @@
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.widget.PopupWindow;
import android.widget.TextView;
public class TooltipPopup {
@@ -33,7 +32,6 @@
private final Context mContext;
- private final PopupWindow mPopupWindow;
private final View mContentView;
private final TextView mMessageView;
@@ -45,8 +43,6 @@
public TooltipPopup(Context context) {
mContext = context;
- mPopupWindow = new PopupWindow(context);
- mPopupWindow.setBackgroundDrawable(null);
mContentView = LayoutInflater.from(mContext).inflate(
com.android.internal.R.layout.tooltip, null);
mMessageView = (TextView) mContentView.findViewById(
@@ -74,16 +70,17 @@
computePosition(anchorView, anchorX, anchorY, fromTouch, mLayoutParams);
- mPopupWindow.setContentView(mContentView);
- mPopupWindow.showAtLocation(
- anchorView, mLayoutParams.gravity, mLayoutParams.x, mLayoutParams.y);
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ wm.addView(mContentView, mLayoutParams);
}
public void hide() {
if (!isShowing()) {
return;
}
- mPopupWindow.dismiss();
+
+ WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ wm.removeView(mContentView);
}
public View getContentView() {
@@ -91,7 +88,7 @@
}
public boolean isShowing() {
- return mPopupWindow.isShowing();
+ return mContentView.getParent() != null;
}
public void updateContent(CharSequence tooltipText) {
@@ -100,6 +97,8 @@
private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
WindowManager.LayoutParams outParams) {
+ outParams.token = anchorView.getWindowToken();
+
final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset(
com.android.internal.R.dimen.tooltip_precise_anchor_threshold);
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index de67c50..26b0034 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/stringprintf.h>
#include <binder/IInterface.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
@@ -194,10 +195,34 @@
/*
* It's an Error: Reraise the exception and ask the runtime to abort.
*/
+
+ // Try to get the exception string. Sometimes logcat isn't available,
+ // so try to add it to the abort message.
+ std::string exc_msg = "(Unknown exception message)";
+ {
+ ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep));
+ jmethodID method_id = env->GetMethodID(exc_class.get(),
+ "toString",
+ "()Ljava/lang/String;");
+ ScopedLocalRef<jstring> jstr(
+ env,
+ reinterpret_cast<jstring>(
+ env->CallObjectMethod(excep, method_id)));
+ env->ExceptionClear(); // Just for good measure.
+ if (jstr.get() != nullptr) {
+ ScopedUtfChars jstr_utf(env, jstr.get());
+ exc_msg = jstr_utf.c_str();
+ }
+ }
+
env->Throw(excep);
ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
env->ExceptionDescribe();
- env->FatalError("java.lang.Error thrown during binder transaction.");
+
+ std::string error_msg = base::StringPrintf(
+ "java.lang.Error thrown during binder transaction: %s",
+ exc_msg.c_str());
+ env->FatalError(error_msg.c_str());
}
bail:
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f8044e2..794d4f8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -453,6 +453,7 @@
<protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
<protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
+ <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
<protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
<protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 7e8bc00..236c185 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -811,7 +811,7 @@
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Confirmació de la navegació"</string>
<string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Surt d\'aquesta pàgina"</string>
<string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Queda\'t en aquesta pàgina"</string>
- <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nEstàs segur que vols sortir d\'aquesta pàgina?"</string>
+ <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nConfirmes que vols sortir d\'aquesta pàgina?"</string>
<string name="save_password_label" msgid="6860261758665825069">"Confirma"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Consell: Pica dos cops per ampliar i per reduir."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Em. aut."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 320ffcb..3251771 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1575,8 +1575,8 @@
<string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
<string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
<string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
- <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Ukendt portrætformat"</string>
- <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Ukendt landskabsformat"</string>
+ <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Ukendt stående format"</string>
+ <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Ukendt liggende format"</string>
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annulleret"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fejl ved skrivning af indhold"</string>
<string name="reason_unknown" msgid="6048913880184628119">"ukendt"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 82c0f63..26f3f1d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -90,7 +90,7 @@
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Η υπηρεσία δεν προβλέπεται."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Δεν μπορείτε να αλλάξετε τη ρύθμιση του αναγνωριστικού καλούντος."</string>
<string name="RestrictedOnDataTitle" msgid="1322504692764166532">"Δεν υπάρχει υπηρεσία δεδομένων"</string>
- <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Αδυναμία πραγματοποίησης κλήσεων έκτακτης ανάγκης"</string>
+ <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Δεν επιτρέπονται οι κλήσεις έκτακτης ανάγκης"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Δεν υπάρχει φωνητική υπηρεσία"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Δεν υπάρχει φωνητική υπηρεσία/υπηρεσία έκτακτης ανάγκης"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Δεν προσφέρεται προσωρινά από το δίκτυο κινητής τηλεφωνίας στην τοποθεσία σας"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index a2b4499..b9b202f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -90,7 +90,7 @@
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
<string name="RestrictedOnDataTitle" msgid="1322504692764166532">"Aucun service de données"</string>
- <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Aucune appel d\'urgence"</string>
+ <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"Aucun appel d\'urgence"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Aucun service vocal"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Aucun service vocal ou d\'urgence"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"Ce service est temporairement non offert par le réseau cellulaire à l\'endroit où vous êtes"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b03d6cc..bf04d8a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1201,7 +1201,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"दूसरे ऐप्लिकेशन पर प्रदर्शित करें"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"दूसरे ऐप्लिकेशन के ऊपर दिखाएं"</string>
<string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप्लिकेशन के ऊपर दिखाई दे रहा है"</string>
<string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्य ऐप पर दिखाई दे रहा है"</string>
<string name="alert_windows_notification_message" msgid="8917232109522912560">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने और उसे बंद करने के लिए टैप करें."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 7135060..ef34aa5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -93,7 +93,7 @@
<string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"긴급 전화 차단됨"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"음성 서비스를 이용할 수 없음"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"음성/긴급 서비스를 이용할 수 없음"</string>
- <string name="RestrictedStateContent" msgid="4278821484643362350">"현재 위치에서 모바일 네트워크가 긴급 서비스 제공을 일시적으로 중단했습니다."</string>
+ <string name="RestrictedStateContent" msgid="4278821484643362350">"현재 위치에서 모바일 네트워크가 서비스 제공을 일시적으로 중단했습니다."</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"네트워크에 연결할 수 없습니다."</string>
<string name="NetworkPreferenceSwitchSummary" msgid="4164230263214915351">"수신 상태를 개선하려면 시스템 > 네트워크 및 인터넷 > 모바일 네트워크 > 기본 네트워크 유형에서 선택된 유형을 변경해 보세요."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"알림"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 6daa7a7..db4d8fc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1202,7 +1202,7 @@
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"အခြားအက်ပ်များအပေါ်တွင် ပြသခွင့် ပြုခြင်း"</string>
+ <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"အခြားအက်ပ်များအပေါ်တွင် ပြသခြင်း"</string>
<string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> သည် အခြားအက်ပ်များအပေါ်တွင် ပြပါသည်"</string>
<string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> ကို အခြားအက်ပ်များပေါ်တွင် မြင်နေရပါသည်။"</string>
<string name="alert_windows_notification_message" msgid="8917232109522912560">"<xliff:g id="NAME">%s</xliff:g> ကို ဤဝန်ဆောင်မှုအား အသုံးမပြုစေလိုလျှင် ဆက်တင်ကို တို့၍ ဖွင့်ပြီး ၎င်းကို ပိတ်လိုက်ပါ။"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index df8d6d2..f64719c 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -90,7 +90,7 @@
<string name="serviceNotProvisioned" msgid="8614830180508686666">"ਸੇਵਾ ਪ੍ਰਬੰਧਿਤ ਨਹੀਂ ਹੈ।"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"ਤੁਸੀਂ ਕਾਲਰ ID ਸੈਟਿੰਗ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।"</string>
<string name="RestrictedOnDataTitle" msgid="1322504692764166532">"ਕੋਈ ਡੈਟਾ ਸੇਵਾ ਨਹੀਂ"</string>
- <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"ਕੋਈ ਸੰਕਟਕਾਲੀਨ ਕਾਲਿੰਗ ਨਹੀਂ"</string>
+ <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"ਸੰਕਟਕਾਲ ਵਿੱਚ ਕੋਈ ਕਾਲ ਨਹੀਂ"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"ਕੋਈ ਆਵਾਜ਼ੀ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ਕੋਈ ਆਵਾਜ਼ੀ/ਸੰਕਟਕਾਲੀਨ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ਤੁਹਾਡੇ ਟਿਕਾਣੇ \'ਤੇ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਉਪਲਬਧ ਨਹੀਂ ਕਰਵਾਈ ਗਈ"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 844dceb..ba1963f 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -90,7 +90,7 @@
<string name="serviceNotProvisioned" msgid="8614830180508686666">"సేవ కేటాయించబడలేదు."</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"మీరు కాలర్ ID సెట్టింగ్ను మార్చలేరు."</string>
<string name="RestrictedOnDataTitle" msgid="1322504692764166532">"డేటా సేవ లేదు"</string>
- <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"అత్యవసర కాలింగ్ లేదు"</string>
+ <string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"అత్యవసర కాలింగ్ సదుపాయం లేదు"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"వాయిస్ సేవ లేదు"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"వాయిస్/అత్యవసర సేవ లేదు"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"మీ స్థానంలో మొబైల్ నెట్వర్క్ ద్వారా తాత్కాలికంగా అందించబడదు"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 6df02eb..526a8d0 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -329,7 +329,7 @@
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى يكتمل الشحن"</string>
<string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"غير معروف"</string>
- <string name="battery_info_status_charging" msgid="1705179948350365604">"جاري الشحن"</string>
+ <string name="battery_info_status_charging" msgid="1705179948350365604">"جارٍ الشحن"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"جارٍ الشحن"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 35a341a..48bf180 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -272,7 +272,7 @@
<string name="app_process_limit_title" msgid="4280600650253107163">"Límita processos en segon pla"</string>
<string name="show_all_anrs" msgid="28462979638729082">"Tots els errors sense resposta"</string>
<string name="show_all_anrs_summary" msgid="641908614413544127">"Informa que una aplicació en segon pla no respon"</string>
- <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Avisos del canal de notificacions"</string>
+ <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostra avisos del canal de notificacions"</string>
<string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra un avís a la pantalla quan una app publica una notificació sense canal vàlid"</string>
<string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string>
<string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f745956..1ec52e7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1864,12 +1864,7 @@
+ " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags));
}
- if (!(mContext instanceof Activity)) {
- final int finalFlags = flags;
- mUiOffloadThread.submit(() -> {
- mStatusBarManager.disable(finalFlags);
- });
- }
+ mStatusBarManager.disable(flags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
index 867c15c..6733421 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -21,12 +21,15 @@
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
import android.view.InputChannel;
import android.view.InputEvent;
-import android.view.InputEventReceiver;
import android.view.IWindowManager;
import android.view.MotionEvent;
+import com.android.systemui.recents.misc.Utilities;
+
import java.io.PrintWriter;
/**
@@ -52,12 +55,13 @@
}
/**
- * Input handler used for the PiP input consumer.
+ * Input handler used for the PiP input consumer. Input events are batched and consumed with the
+ * SurfaceFlinger vsync.
*/
- private final class PipInputEventReceiver extends InputEventReceiver {
+ private final class PipInputEventReceiver extends BatchedInputEventReceiver {
public PipInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
+ super(inputChannel, looper, Choreographer.getSfInstance());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 013b9ac..0f69f47 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -573,13 +573,11 @@
}
private void cancelDelayedFinish() {
- View v = getWindow().getDecorView();
- v.removeCallbacks(mFinishRunnable);
+ mHandler.removeCallbacks(mFinishRunnable);
}
private void repostDelayedFinish(long delay) {
- View v = getWindow().getDecorView();
- v.removeCallbacks(mFinishRunnable);
- v.postDelayed(mFinishRunnable, delay);
+ mHandler.removeCallbacks(mFinishRunnable);
+ mHandler.postDelayed(mFinishRunnable, delay);
}
}
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 9fa7ff6..b8771d7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -22,6 +22,7 @@
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
+import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
@@ -36,14 +37,15 @@
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Choreographer;
import android.view.animation.Interpolator;
-import com.android.internal.os.BackgroundThread;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.internal.os.SomeArgs;
import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
+import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -52,7 +54,7 @@
/**
* A helper to animate and manipulate the PiP.
*/
-public class PipMotionHelper {
+public class PipMotionHelper implements Handler.Callback {
private static final String TAG = "PipMotionHelper";
private static final boolean DEBUG = false;
@@ -74,38 +76,34 @@
// The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
+ private static final int MSG_RESIZE_IMMEDIATE = 1;
+ private static final int MSG_RESIZE_ANIMATE = 2;
+
private Context mContext;
private IActivityManager mActivityManager;
- private SurfaceFlingerVsyncChoreographer mVsyncChoreographer;
private Handler mHandler;
private PipMenuActivityController mMenuController;
private PipSnapAlgorithm mSnapAlgorithm;
private FlingAnimationUtils mFlingAnimationUtils;
+ private AnimationHandler mAnimationHandler;
private final Rect mBounds = new Rect();
private final Rect mStableInsets = new Rect();
private ValueAnimator mBoundsAnimator = null;
- private ValueAnimator.AnimatorUpdateListener mUpdateBoundsListener =
- new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mBounds.set((Rect) animation.getAnimatedValue());
- }
- };
public PipMotionHelper(Context context, IActivityManager activityManager,
PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
FlingAnimationUtils flingAnimationUtils) {
mContext = context;
- mHandler = BackgroundThread.getHandler();
+ mHandler = new Handler(ForegroundThread.get().getLooper(), this);
mActivityManager = activityManager;
mMenuController = menuController;
mSnapAlgorithm = snapAlgorithm;
mFlingAnimationUtils = flingAnimationUtils;
- mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(),
- Choreographer.getInstance());
+ mAnimationHandler = new AnimationHandler();
+ mAnimationHandler.setProvider(new SfVsyncFrameCallbackProvider());
onConfigurationChanged();
}
@@ -252,8 +250,7 @@
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
0 /* velocityX */, velocityY);
if (!mBounds.equals(toBounds)) {
- mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
- mUpdateBoundsListener);
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
distanceBetweenRectOffsets(mBounds, toBounds),
velocityY);
@@ -271,7 +268,7 @@
Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds,
- MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener);
+ MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN);
if (updateListener != null) {
mBoundsAnimator.addUpdateListener(updateListener);
}
@@ -289,8 +286,7 @@
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
velocityX, velocityY);
if (!mBounds.equals(toBounds)) {
- mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN,
- mUpdateBoundsListener);
+ mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
distanceBetweenRectOffsets(mBounds, toBounds),
velocity);
@@ -314,7 +310,7 @@
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
- FAST_OUT_SLOW_IN, mUpdateBoundsListener);
+ FAST_OUT_SLOW_IN);
if (updateListener != null) {
mBoundsAnimator.addUpdateListener(updateListener);
}
@@ -379,7 +375,7 @@
Rect toBounds = new Rect(pipBounds);
toBounds.offsetTo(p.x, p.y);
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DRAG_TO_DISMISS_STACK_DURATION,
- FAST_OUT_LINEAR_IN, mUpdateBoundsListener);
+ FAST_OUT_LINEAR_IN);
mBoundsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -411,16 +407,20 @@
* Creates an animation to move the PiP to give given {@param toBounds}.
*/
private ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration,
- Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) {
- ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds);
+ Interpolator interpolator) {
+ ValueAnimator anim = new ValueAnimator() {
+ @Override
+ public AnimationHandler getAnimationHandler() {
+ return mAnimationHandler;
+ }
+ };
+ anim.setObjectValues(fromBounds, toBounds);
+ anim.setEvaluator(RECT_EVALUATOR);
anim.setDuration(duration);
anim.setInterpolator(interpolator);
anim.addUpdateListener((ValueAnimator animation) -> {
resizePipUnchecked((Rect) animation.getAnimatedValue());
});
- if (updateListener != null) {
- anim.addUpdateListener(updateListener);
- }
return anim;
}
@@ -433,14 +433,9 @@
+ " callers=\n" + Debug.getCallers(5, " "));
}
if (!toBounds.equals(mBounds)) {
- mVsyncChoreographer.scheduleAtSfVsync(() -> {
- try {
- mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
- mBounds.set(toBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e);
- }
- });
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = toBounds;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
}
}
@@ -453,23 +448,10 @@
+ " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
}
if (!toBounds.equals(mBounds)) {
- mHandler.post(() -> {
- try {
- StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
- if (stackInfo == null) {
- // In the case where we've already re-expanded or dismissed the PiP, then
- // just skip the resize
- return;
- }
-
- mActivityManager.resizeStack(PINNED_STACK_ID, toBounds,
- false /* allowResizeInDockedMode */, true /* preserveWindows */,
- true /* animate */, duration);
- mBounds.set(toBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
- }
- });
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = toBounds;
+ args.argi1 = duration;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
}
}
@@ -524,6 +506,50 @@
return PointF.length(r1.left - r2.left, r1.top - r2.top);
}
+ /**
+ * Handles messages to be processed on the background thread.
+ */
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_RESIZE_IMMEDIATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Rect toBounds = (Rect) args.arg1;
+ try {
+ mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e);
+ }
+ return true;
+ }
+
+ case MSG_RESIZE_ANIMATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Rect toBounds = (Rect) args.arg1;
+ int duration = args.argi1;
+ try {
+ StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo == null) {
+ // In the case where we've already re-expanded or dismissed the PiP, then
+ // just skip the resize
+ return true;
+ }
+
+ mActivityManager.resizeStack(PINNED_STACK_ID, toBounds,
+ false /* allowResizeInDockedMode */, true /* preserveWindows */,
+ true /* animate */, duration);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
+ }
+ return true;
+ }
+
+ default:
+ return false;
+ }
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 9b20a7a..79fb5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -179,12 +179,6 @@
@Override
public void onBluetoothDevicesChanged() {
- mUiHandler.post(new Runnable() {
- @Override
- public void run() {
- mDetailAdapter.updateItems();
- }
- });
refreshState();
if (isShowingDetail()) {
mDetailAdapter.updateItems();
@@ -198,6 +192,9 @@
}
protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
+ // We probably won't ever have space in the UI for more than 20 devices, so don't
+ // get info for them.
+ private static final int MAX_DEVICES = 20;
private QSDetailItems mItems;
@Override
@@ -260,13 +257,14 @@
final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) {
int connectedDevices = 0;
+ int count = 0;
for (CachedBluetoothDevice device : devices) {
- if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
+ if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
item.icon = R.drawable.ic_qs_bluetooth_on;
item.line1 = device.getName();
item.tag = device;
- int state = device.getMaxConnectionState();
+ int state = mController.getMaxConnectionState(device);
if (state == BluetoothProfile.STATE_CONNECTED) {
item.icon = R.drawable.ic_qs_bluetooth_connected;
item.line2 = mContext.getString(R.string.quick_settings_connected);
@@ -280,6 +278,9 @@
} else {
items.add(item);
}
+ if (++count == MAX_DEVICES) {
+ break;
+ }
}
}
mItems.setItems(items.toArray(new Item[items.size()]));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 1f13830..c66b2dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -154,6 +154,13 @@
Canvas mBgProtectionCanvas;
private final Handler mHandler = new H();
+ private final Runnable mGcRunnable = new Runnable() {
+ @Override
+ public void run() {
+ System.gc();
+ System.runFinalization();
+ }
+ };
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
@@ -365,13 +372,7 @@
* Requests a gc() from the background thread.
*/
public void gc() {
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- System.gc();
- System.runFinalization();
- }
- });
+ BackgroundThread.getHandler().post(mGcRunnable);
}
/**
@@ -799,11 +800,8 @@
if (RecentsDebugFlags.Static.EnableMockTasks) return;
// Remove the task.
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- mAm.removeTask(taskId);
- }
+ mUiOffloadThread.submit(() -> {
+ mAm.removeTask(taskId);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index 1f82c16..308cece 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -20,9 +20,9 @@
import android.os.UserHandle;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.BackgroundThread;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
+import com.android.systemui.recents.misc.ForegroundThread;
/**
* The package monitor listens for changes from PackageManager to update the contents of the
@@ -36,7 +36,7 @@
// We register for events from all users, but will cross-reference them with
// packages for the current user and any profiles they have. Ensure that events are
// handled in a background thread.
- register(context, BackgroundThread.get().getLooper(), UserHandle.ALL, true);
+ register(context, ForegroundThread.get().getLooper(), UserHandle.ALL, true);
} catch (IllegalStateException e) {
e.printStackTrace();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 3b37437..0232911 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -25,6 +25,8 @@
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -56,6 +58,7 @@
SystemServicesProxy ssp = Recents.getSystemServices();
ssp.registerDockedStackListener(mDockDividerVisibilityListener);
mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
+ EventBus.getDefault().register(this);
}
@Override
@@ -153,6 +156,18 @@
mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
}
+ /**
+ * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+ if (mView != null) {
+ mView.onRecentsDrawn();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print(" mVisible="); pw.println(mVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 6dc7870..7691652 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1222,7 +1222,7 @@
mSnapAlgorithm.getMiddleTarget());
}
- public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+ public void onRecentsDrawn() {
if (mState.animateAfterRecentsDrawn) {
mState.animateAfterRecentsDrawn = false;
updateDockSide();
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 bb302bb..47c4692 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -92,6 +92,7 @@
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
+ private boolean mLastDeferScrimFadeOut;
private OnDismissAction mAfterKeyguardGoneAction;
private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
@@ -367,7 +368,6 @@
mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
mFingerprintUnlockController.startKeyguardFadingAway();
mBouncer.hide(true /* destroyView */);
- updateStates();
if (wakeUnlockPulsing) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
mStatusBar.fadeKeyguardWhilePulsing();
@@ -399,6 +399,7 @@
mFingerprintUnlockController.finishKeyguardFadingAway();
}
}
+ updateStates();
mStatusBarWindowManager.setKeyguardShowing(false);
mViewMediatorCallback.keyguardGone();
}
@@ -569,7 +570,7 @@
mLastBouncerShowing = bouncerShowing;
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
-
+ mLastDeferScrimFadeOut = mDeferScrimFadeOut;
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
@@ -577,14 +578,16 @@
* @return Whether the navigation bar should be made visible based on the current state.
*/
protected boolean isNavBarVisible() {
- return !(mShowing && !mOccluded) || mBouncer.isShowing() || mRemoteInputActive;
+ return (!(mShowing && !mOccluded) || mBouncer.isShowing() || mRemoteInputActive)
+ && !mDeferScrimFadeOut;
}
/**
* @return Whether the navigation bar was made visible based on the last known state.
*/
protected boolean getLastNavBarVisible() {
- return !(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive;
+ return (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive)
+ && !mLastDeferScrimFadeOut;
}
public boolean shouldDismissOnMenuPressed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index df30e20..9daa199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -37,6 +37,9 @@
void disconnect(CachedBluetoothDevice device);
boolean canConfigBluetooth();
+ int getMaxConnectionState(CachedBluetoothDevice device);
+ int getBondState(CachedBluetoothDevice device);
+
public interface Callback {
void onBluetoothStateChange(boolean enabled);
void onBluetoothDevicesChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 36d24b3..dc4b115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -18,6 +18,8 @@
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -33,8 +35,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.WeakHashMap;
public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
CachedBluetoothDevice.Callback {
@@ -44,18 +48,22 @@
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
+ private final WeakHashMap<CachedBluetoothDevice, ActuallyCachedState> mCachedState =
+ new WeakHashMap<>();
+ private final Handler mBgHandler;
private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
private CachedBluetoothDevice mLastDevice;
- private final H mHandler = new H();
+ private final H mHandler = new H(Looper.getMainLooper());
private int mState;
public BluetoothControllerImpl(Context context, Looper bgLooper) {
mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class);
+ mBgHandler = new Handler(bgLooper);
if (mLocalBluetoothManager != null) {
- mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper));
+ mLocalBluetoothManager.getEventManager().setReceiverHandler(mBgHandler);
mLocalBluetoothManager.getEventManager().registerCallback(this);
onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
@@ -106,6 +114,16 @@
}
@Override
+ public int getBondState(CachedBluetoothDevice device) {
+ return getCachedState(device).mBondState;
+ }
+
+ @Override
+ public int getMaxConnectionState(CachedBluetoothDevice device) {
+ return getCachedState(device).mMaxConnectionState;
+ }
+
+ @Override
public void addCallback(Callback cb) {
mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
@@ -225,12 +243,14 @@
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
+ mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@@ -243,11 +263,44 @@
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+ mCachedState.remove(cachedDevice);
mLastDevice = cachedDevice;
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
+ private ActuallyCachedState getCachedState(CachedBluetoothDevice device) {
+ ActuallyCachedState state = mCachedState.get(device);
+ if (state == null) {
+ state = new ActuallyCachedState(device, mHandler);
+ mBgHandler.post(state);
+ mCachedState.put(device, state);
+ return state;
+ }
+ return state;
+ }
+
+ private static class ActuallyCachedState implements Runnable {
+
+ private final WeakReference<CachedBluetoothDevice> mDevice;
+ private final Handler mUiHandler;
+ private int mBondState = BluetoothDevice.BOND_NONE;
+ private int mMaxConnectionState = BluetoothProfile.STATE_DISCONNECTED;
+
+ private ActuallyCachedState(CachedBluetoothDevice device, Handler uiHandler) {
+ mDevice = new WeakReference<>(device);
+ mUiHandler = uiHandler;
+ }
+
+ @Override
+ public void run() {
+ mBondState = mDevice.get().getBondState();
+ mMaxConnectionState = mDevice.get().getMaxConnectionState();
+ mUiHandler.removeMessages(H.MSG_PAIRED_DEVICES_CHANGED);
+ mUiHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
+ }
+ }
+
private final class H extends Handler {
private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
@@ -256,6 +309,10 @@
private static final int MSG_ADD_CALLBACK = 3;
private static final int MSG_REMOVE_CALLBACK = 4;
+ public H(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 2eb9560..4cc8bca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -14,16 +14,21 @@
package com.android.systemui.statusbar.policy;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -80,4 +85,56 @@
BluetoothAdapter.STATE_DISCONNECTED);
assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
}
+
+ @Test
+ public void testDefaultConnectionState() {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
+ assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+ }
+
+ @Test
+ public void testAsyncBondState() throws Exception {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
+ mBluetoothControllerImpl.addCallback(callback);
+
+ // Grab the main looper, we'll need it later.
+ TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
+
+ // Trigger the state getting.
+ assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
+
+ mTestableLooper.processMessages(1);
+ mainLooper.processAllMessages();
+
+ assertEquals(BluetoothDevice.BOND_BONDED, mBluetoothControllerImpl.getBondState(device));
+ verify(callback).onBluetoothDevicesChanged();
+ mainLooper.destroy();
+ }
+
+ @Test
+ public void testAsyncConnectionState() throws Exception {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
+ BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
+ mBluetoothControllerImpl.addCallback(callback);
+
+ // Grab the main looper, we'll need it later.
+ TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
+
+ // Trigger the state getting.
+ assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+
+ mTestableLooper.processMessages(1);
+ mainLooper.processAllMessages();
+
+ assertEquals(BluetoothProfile.STATE_CONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+ verify(callback).onBluetoothDevicesChanged();
+ mainLooper.destroy();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
index 0ba0319..9ec096a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
@@ -83,4 +83,14 @@
public boolean canConfigBluetooth() {
return false;
}
+
+ @Override
+ public int getMaxConnectionState(CachedBluetoothDevice device) {
+ return 0;
+ }
+
+ @Override
+ public int getBondState(CachedBluetoothDevice device) {
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6a310f2..eeab605 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -599,6 +599,7 @@
void finishUserStopping(final int userId, final UserState uss) {
// On to the next.
final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+ shutdownIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
// This is the result receiver for the final shutdown broadcast.
final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
@Override
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 34cc6e3..d0d306c 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -121,8 +121,11 @@
resolutionStatus = RESOLUTION_FAILURE;
}
}
- logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token,
- resolutionStatus);
+ // Only log successful instant application resolution
+ if (resolutionStatus == RESOLUTION_SUCCESS) {
+ logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token,
+ resolutionStatus);
+ }
if (DEBUG_EPHEMERAL && resolveInfo == null) {
if (resolutionStatus == RESOLUTION_BIND_TIMEOUT) {
Log.d(TAG, "[" + token + "] Phase1; bind timed out");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 75e7a1e..62b563a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -81,8 +81,10 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.Xml;
+import java.io.CharArrayWriter;
import libcore.io.IoUtils;
import com.android.internal.R;
@@ -195,7 +197,10 @@
/** Historical sessions kept around for debugging purposes */
@GuardedBy("mSessions")
- private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>();
+ private final List<String> mHistoricalSessions = new ArrayList<>();
+
+ @GuardedBy("mSessions")
+ private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
/** Sessions allocated to legacy users */
@GuardedBy("mSessions")
@@ -371,7 +376,7 @@
// Since this is early during boot we don't send
// any observer events about the session, but we
// keep details around for dumpsys.
- mHistoricalSessions.put(session.sessionId, session);
+ addHistoricalSessionLocked(session);
}
mAllocatedSessions.put(session.sessionId, true);
}
@@ -386,6 +391,18 @@
}
}
+ private void addHistoricalSessionLocked(PackageInstallerSession session) {
+ CharArrayWriter writer = new CharArrayWriter();
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ session.dump(pw);
+ mHistoricalSessions.add(writer.toString());
+
+ // Increment the number of sessions by this installerUid.
+ mHistoricalSessionsByInstaller.put(
+ session.installerUid,
+ mHistoricalSessionsByInstaller.get(session.installerUid) + 1);
+ }
+
private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException,
XmlPullParserException {
final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
@@ -676,7 +693,7 @@
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
- final int historicalCount = getSessionCount(mHistoricalSessions, callingUid);
+ final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
throw new IllegalStateException(
"Too many historical sessions for UID " + callingUid);
@@ -1228,8 +1245,7 @@
pw.increaseIndent();
N = mHistoricalSessions.size();
for (int i = 0; i < N; i++) {
- final PackageInstallerSession session = mHistoricalSessions.valueAt(i);
- session.dump(pw);
+ pw.print(mHistoricalSessions.get(i));
pw.println();
}
pw.println();
@@ -1264,7 +1280,7 @@
public void run() {
synchronized (mSessions) {
mSessions.remove(session.sessionId);
- mHistoricalSessions.put(session.sessionId, session);
+ addHistoricalSessionLocked(session);
final File appIconFile = buildAppIconFile(session.sessionId);
if (appIconFile.exists()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e62b107..27107af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -48,6 +48,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
@@ -17837,16 +17838,17 @@
// Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target O, this will be a fatal error.");
- // STOPSHIP: Make this a fatal error
- pkg.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
+ res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Instant app package must target O");
+ return;
}
if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target targetSandboxVersion 2, this will be a fatal error.");
- // STOPSHIP: Make this a fatal error
- pkg.applicationInfo.targetSandboxVersion = 2;
+ + " does not target targetSandboxVersion 2");
+ res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Instant app package must use targetSanboxVersion 2");
+ return;
}
if (pkg.applicationInfo.isStaticSharedLibrary()) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c2c9123..01eabd8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3072,13 +3072,18 @@
if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
+ ": transit=" + transit);
if (win == mStatusBar) {
- boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ final boolean expanded = win.getAttrs().height == MATCH_PARENT
+ && win.getAttrs().width == MATCH_PARENT;
+ if (isKeyguard || expanded) {
+ return -1;
+ }
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
- return isKeyguard ? -1 : R.anim.dock_top_exit;
+ return R.anim.dock_top_exit;
} else if (transit == TRANSIT_ENTER
|| transit == TRANSIT_SHOW) {
- return isKeyguard ? -1 : R.anim.dock_top_enter;
+ return R.anim.dock_top_enter;
}
} else if (win == mNavigationBar) {
if (win.getAttrs().windowAnimations != 0) {
@@ -6803,7 +6808,9 @@
@Override
public boolean isScreenOn() {
- return mScreenOnFully;
+ synchronized (mLock) {
+ return mScreenOnEarly;
+ }
}
/** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 864e83e..02f2afc 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -256,7 +256,7 @@
ProgressDialog pd = new ProgressDialog(context);
// Path 1: Reboot to recovery for update
- // Condition: mReason == REBOOT_RECOVERY_UPDATE
+ // Condition: mReason startswith REBOOT_RECOVERY_UPDATE
//
// Path 1a: uncrypt needed
// Condition: if /cache/recovery/uncrypt_file exists but
@@ -276,7 +276,9 @@
// Path 3: Regular reboot / shutdown
// Condition: Otherwise
// UI: spinning circle only (no progress bar)
- if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
+
+ // mReason could be "recovery-update" or "recovery-update,quiescent".
+ if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
// We need the progress bar if uncrypt will be invoked during the
// reboot, which might be time-consuming.
mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
@@ -295,7 +297,7 @@
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_update_reboot));
}
- } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
+ } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
// Factory reset path. Set the dialog message accordingly.
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
pd.setMessage(context.getText(
@@ -389,7 +391,8 @@
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 410efcd..7d13889 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -20,6 +20,8 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.animation.AnimationHandler;
+import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
@@ -30,11 +32,13 @@
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.Choreographer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.WindowManagerInternal;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -49,7 +53,7 @@
*
* The object that is resized needs to implement {@link BoundsAnimationTarget} interface.
*
- * NOTE: All calls to methods in this class should be done on the UI thread
+ * NOTE: All calls to methods in this class should be done on the Animation thread
*/
public class BoundsAnimationController {
private static final boolean DEBUG_LOCAL = false;
@@ -111,20 +115,24 @@
private final AppTransitionNotifier mAppTransitionNotifier = new AppTransitionNotifier();
private final Interpolator mFastOutSlowInInterpolator;
private boolean mFinishAnimationAfterTransition = false;
+ private final AnimationHandler mAnimationHandler;
private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
- BoundsAnimationController(Context context, AppTransition transition, Handler handler) {
+ BoundsAnimationController(Context context, AppTransition transition, Handler handler,
+ AnimationHandler animationHandler) {
mHandler = handler;
mAppTransition = transition;
mAppTransition.registerListenerLocked(mAppTransitionNotifier);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
+ mAnimationHandler = animationHandler;
}
@VisibleForTesting
final class BoundsAnimator extends ValueAnimator
implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+
private final BoundsAnimationTarget mTarget;
private final Rect mFrom = new Rect();
private final Rect mTo = new Rect();
@@ -350,6 +358,14 @@
public void onAnimationRepeat(Animator animation) {
// Do nothing
}
+
+ @Override
+ public AnimationHandler getAnimationHandler() {
+ if (mAnimationHandler != null) {
+ return mAnimationHandler;
+ }
+ return super.getAnimationHandler();
+ }
}
public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ccc8f63..54983c8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -314,6 +314,9 @@
// the display's direct children should be allowed.
private boolean mRemovingDisplay = false;
+ // {@code false} if this display is in the processing of being created.
+ private boolean mDisplayReady = false;
+
private final WindowLayersController mLayersController;
WallpaperController mWallpaperController;
int mInputMethodAnimLayerAdjustment;
@@ -720,7 +723,6 @@
*/
DisplayContent(Display display, WindowManagerService service,
WindowLayersController layersController, WallpaperController wallpaperController) {
-
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -748,6 +750,15 @@
// Add itself as a child to the root container.
mService.mRoot.addChild(this, null);
+
+ // TODO(b/62541591): evaluate whether this is the best spot to declare the
+ // {@link DisplayContent} ready for use.
+ mDisplayReady = true;
+ }
+
+ boolean isReady() {
+ // The display is ready when the system and the individual display are both ready.
+ return mService.mDisplayReady && mDisplayReady;
}
int getDisplayId() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 03b5b827..aabf2be 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -108,7 +108,8 @@
}
void addDisplayLocked(final int displayId) {
- // Create the DisplayContentsAnimator object by retrieving it.
+ // Create the DisplayContentsAnimator object by retrieving it if the associated
+ // {@link DisplayContent} exists.
getDisplayContentsAnimatorLocked(displayId);
if (displayId == DEFAULT_DISPLAY) {
mInitialized = true;
@@ -356,8 +357,16 @@
}
private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
+ if (displayId < 0) {
+ return null;
+ }
+
DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
- if (displayAnimator == null) {
+
+ // It is possible that this underlying {@link DisplayContent} has been removed. In this
+ // case, we do not want to create an animator associated with it as {link #animate} will
+ // fail.
+ if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
displayAnimator = new DisplayContentsAnimator();
mDisplayContentsAnimators.put(displayId, displayAnimator);
}
@@ -365,8 +374,10 @@
}
void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
- if (displayId >= 0) {
- getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+ final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
+
+ if (animator != null) {
+ animator.mScreenRotationAnimation = animation;
}
}
@@ -374,7 +385,9 @@
if (displayId < 0) {
return null;
}
- return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
+
+ DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
+ return animator != null? animator.mScreenRotationAnimation : null;
}
void requestRemovalOfReplacedWindows(WindowState win) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 768b03a..9e3edef 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -103,6 +103,7 @@
import android.Manifest;
import android.Manifest.permission;
+import android.animation.AnimationHandler;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -211,6 +212,7 @@
import com.android.internal.R;
import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -1046,8 +1048,10 @@
mAppTransition = new AppTransition(context, this);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
+ final AnimationHandler animationHandler = new AnimationHandler();
+ animationHandler.setProvider(new SfVsyncFrameCallbackProvider());
mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
- UiThread.getHandler());
+ AnimationThread.getHandler(), animationHandler);
mActivityManager = ActivityManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -5886,8 +5890,8 @@
return;
}
- if (!mDisplayReady || !mPolicy.isScreenOn()) {
- // No need to freeze the screen before the system is ready or if
+ if (!displayContent.isReady() || !mPolicy.isScreenOn()) {
+ // No need to freeze the screen before the display is ready, system is ready, or if
// the screen is off.
return;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6f53099..cc39271 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -449,7 +449,7 @@
// If '/cache/recovery/block.map' hasn't been created, stop the
// reboot which will fail for sure, and get a chance to capture a
// bugreport when that's still feasible. (Bug: 26444951)
- if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
+ if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
File packageFile = new File(UNCRYPT_PACKAGE_FILE);
if (packageFile.exists()) {
String filename = null;
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index ee09f4b..9d32496 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -395,7 +395,7 @@
mMockAppTransition = new MockAppTransition(context);
mMockAnimator = new MockValueAnimator();
mTarget = new TestBoundsAnimationTarget();
- mController = new BoundsAnimationController(context, mMockAppTransition, handler);
+ mController = new BoundsAnimationController(context, mMockAppTransition, handler, null);
mDriver = new BoundsAnimationDriver(mController, mTarget);
}