Merge "Import translations. DO NOT MERGE" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 0177e4f..a9bb90f3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4280,6 +4280,7 @@
public class DownloadManager {
method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
+ method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
method public long enqueue(android.app.DownloadManager.Request);
method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
method public java.lang.String getMimeTypeForDownloadedFile(long);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7956826..a9324d9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4412,6 +4412,7 @@
public class DownloadManager {
method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
+ method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
method public long enqueue(android.app.DownloadManager.Request);
method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
method public java.lang.String getMimeTypeForDownloadedFile(long);
diff --git a/api/test-current.txt b/api/test-current.txt
index 264b5eb..84e8b26 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4280,6 +4280,7 @@
public class DownloadManager {
method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
+ method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
method public long enqueue(android.app.DownloadManager.Request);
method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
method public java.lang.String getMimeTypeForDownloadedFile(long);
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 32edd4d..77df151 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -29,8 +29,9 @@
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
* values between those keyframes for a given animation. The class internal to the animation
* package because it is an implementation detail of how Keyframes are stored and used.
+ * @hide
*/
-class KeyframeSet implements Keyframes {
+public class KeyframeSet implements Keyframes {
int mNumKeyframes;
diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java
index c149bed..e40a86c 100644
--- a/core/java/android/animation/Keyframes.java
+++ b/core/java/android/animation/Keyframes.java
@@ -20,8 +20,9 @@
/**
* This interface abstracts a collection of Keyframe objects and is called by
* ValueAnimator to calculate values between those keyframes for a given animation.
+ * @hide
*/
-interface Keyframes extends Cloneable {
+public interface Keyframes extends Cloneable {
/**
* Sets the TypeEvaluator to be used when calculating animated values. This object
diff --git a/core/java/android/animation/PathKeyframes.java b/core/java/android/animation/PathKeyframes.java
index 8230ac5..50a490e 100644
--- a/core/java/android/animation/PathKeyframes.java
+++ b/core/java/android/animation/PathKeyframes.java
@@ -34,8 +34,9 @@
* Typically, the returned type is a PointF, but the individual components can be extracted
* as either an IntKeyframes or FloatKeyframes.
* </p>
+ * @hide
*/
-class PathKeyframes implements Keyframes {
+public class PathKeyframes implements Keyframes {
private static final int FRACTION_OFFSET = 0;
private static final int X_OFFSET = 1;
private static final int Y_OFFSET = 2;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 7310d67..5116634 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -114,4 +114,15 @@
* values.
*/
public abstract void notifyAppTransitionStarting(int reason);
+
+ /**
+ * Callback for window manager to let activity manager know that the app transition was
+ * cancelled.
+ */
+ public abstract void notifyAppTransitionCancelled();
+
+ /**
+ * Callback for window manager to let activity manager know that the app transition is finished.
+ */
+ public abstract void notifyAppTransitionFinished();
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 167e6cb..2846798 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -154,6 +154,12 @@
private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
/**
+ * The task id the activity should be launched into.
+ * @hide
+ */
+ private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
+
+ /**
* Where the docked stack should be positioned.
* @hide
*/
@@ -224,6 +230,7 @@
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
private int mLaunchStackId = INVALID_STACK_ID;
+ private int mLaunchTaskId = -1;
private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
private AppTransitionAnimationSpec mAnimSpecs[];
@@ -766,6 +773,7 @@
break;
}
mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
+ mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
if (opts.containsKey(KEY_ANIM_SPECS)) {
Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
@@ -927,6 +935,21 @@
mLaunchStackId = launchStackId;
}
+ /**
+ * Sets the task the activity will be launched in.
+ * @hide
+ */
+ public void setLaunchTaskId(int taskId) {
+ mLaunchTaskId = taskId;
+ }
+
+ /**
+ * @hide
+ */
+ public int getLaunchTaskId() {
+ return mLaunchTaskId;
+ }
+
/** @hide */
public int getDockCreateMode() {
return mDockCreateMode;
@@ -1079,6 +1102,7 @@
break;
}
b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
+ b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 63a6829..d28f1fb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -803,7 +803,12 @@
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
- if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+
+ // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
+ // generally not allowed, except if the caller specifies the task id the activity should
+ // be launched in.
+ if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+ && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 536c4a8..8bc1aa3 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1193,13 +1193,52 @@
boolean isMediaScannerScannable, String mimeType, String path, long length,
boolean showNotification) {
return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
- length, showNotification, false);
+ length, showNotification, false, null, null);
+ }
+
+ /**
+ * Adds a file to the downloads database system, so it could appear in Downloads App
+ * (and thus become eligible for management by the Downloads App).
+ * <p>
+ * It is helpful to make the file scannable by MediaScanner by setting the param
+ * isMediaScannerScannable to true. It makes the file visible in media managing
+ * applications such as Gallery App, which could be a useful purpose of using this API.
+ *
+ * @param title the title that would appear for this file in Downloads App.
+ * @param description the description that would appear for this file in Downloads App.
+ * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files
+ * scanned by MediaScanner appear in the applications used to view media (for example,
+ * Gallery app).
+ * @param mimeType mimetype of the file.
+ * @param path absolute pathname to the file. The file should be world-readable, so that it can
+ * be managed by the Downloads App and any other app that is used to read it (for example,
+ * Gallery app to display the file, if the file contents represent a video/image).
+ * @param length length of the downloaded file
+ * @param showNotification true if a notification is to be sent, false otherwise
+ * @param uri the original HTTP URI of the download
+ * @param referer the HTTP Referer for the download
+ * @return an ID for the download entry added to the downloads app, unique across the system
+ * This ID is used to make future calls related to this download.
+ */
+ public long addCompletedDownload(String title, String description,
+ boolean isMediaScannerScannable, String mimeType, String path, long length,
+ boolean showNotification, Uri uri, Uri referer) {
+ return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
+ length, showNotification, false, uri, referer);
}
/** {@hide} */
public long addCompletedDownload(String title, String description,
boolean isMediaScannerScannable, String mimeType, String path, long length,
boolean showNotification, boolean allowWrite) {
+ return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
+ length, showNotification, allowWrite, null, null);
+ }
+
+ /** {@hide} */
+ public long addCompletedDownload(String title, String description,
+ boolean isMediaScannerScannable, String mimeType, String path, long length,
+ boolean showNotification, boolean allowWrite, Uri uri, Uri referer) {
// make sure the input args are non-null/non-zero
validateArgumentIsNonEmpty("title", title);
validateArgumentIsNonEmpty("description", description);
@@ -1210,10 +1249,18 @@
}
// if there is already an entry with the given path name in downloads.db, return its id
- Request request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD)
- .setTitle(title)
+ Request request;
+ if (uri != null) {
+ request = new Request(uri);
+ } else {
+ request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD);
+ }
+ request.setTitle(title)
.setDescription(description)
.setMimeType(mimeType);
+ if (referer != null) {
+ request.addRequestHeader("Referer", referer.toString());
+ }
ContentValues values = request.toContentValues(null);
values.put(Downloads.Impl.COLUMN_DESTINATION,
Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 6432558..fa67529 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -35,4 +35,9 @@
* Called whenever the pinned stack is done animating a resize.
*/
void onPinnedStackAnimationEnded();
+
+ /**
+ * Called when we launched an activity that we forced to be resizable.
+ */
+ void onActivityForcedResizable(String packageName, int taskId);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index de8b690..d0029e1 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -91,6 +91,12 @@
/** The name of the hardware (from the kernel command line or /proc). */
public static final String HARDWARE = getString("ro.hardware");
+ /**
+ * Whether this build was for an emulator device.
+ * @hide
+ */
+ public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
+
/** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
public static final String SERIAL = getString("ro.serialno");
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 100f6a1..24a6cdf 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -293,7 +293,9 @@
/**
* Control network activity of a UID over interfaces with a quota limit.
*/
- void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
+ void setUidMeteredNetworkBlacklist(int uid, boolean enable);
+ void setUidMeteredNetworkWhitelist(int uid, boolean enable);
+ boolean setDataSaverModeEnabled(boolean enable);
void setUidCleartextNetworkPolicy(int uid, int policy);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7c06577..9418aaf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,7 +16,8 @@
package android.view;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
+import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -96,8 +97,8 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
import java.util.HashSet;
+import java.util.concurrent.CountDownLatch;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -146,9 +147,6 @@
*/
static final int MAX_TRACKBALL_DELAY = 250;
- private static final int RESIZE_MODE_FREEFORM = 0;
- private static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
-
static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
@@ -233,6 +231,7 @@
boolean mIsAnimating;
private boolean mDragResizing;
+ private boolean mInvalidateRootRequested;
private int mResizeMode;
private int mCanvasOffsetX;
private int mCanvasOffsetY;
@@ -1828,12 +1827,12 @@
final boolean dragResizing = freeformResizing || dockedResizing;
if (mDragResizing != dragResizing) {
if (dragResizing) {
- startDragResizing(mPendingBackDropFrame,
- mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
- mPendingStableInsets);
mResizeMode = freeformResizing
? RESIZE_MODE_FREEFORM
: RESIZE_MODE_DOCKED_DIVIDER;
+ startDragResizing(mPendingBackDropFrame,
+ mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
+ mPendingStableInsets, mResizeMode);
} else {
// We shouldn't come here, but if we come we should end the resize.
endDragResizing();
@@ -2438,6 +2437,11 @@
@Override
public void onHardwarePostDraw(DisplayListCanvas canvas) {
drawAccessibilityFocusedDrawableIfNeeded(canvas);
+ synchronized (mWindowCallbacks) {
+ for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
+ mWindowCallbacks.get(i).onPostDraw(canvas);
+ }
+ }
}
/**
@@ -2675,7 +2679,8 @@
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
// If accessibility focus moved, always invalidate the root.
- boolean invalidateRoot = accessibilityFocusDirty;
+ boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
+ mInvalidateRootRequested = false;
// Draw with hardware renderer.
mIsAnimating = false;
@@ -2908,6 +2913,14 @@
return mAttachInfo.mAccessibilityFocusDrawable;
}
+ /**
+ * Requests that the root render node is invalidated next time we perform a draw, such that
+ * {@link WindowCallbacks#onPostDraw} gets called.
+ */
+ public void requestInvalidateRootRenderNode() {
+ mInvalidateRootRequested = true;
+ }
+
boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
final Rect ci = mAttachInfo.mContentInsets;
final Rect vi = mAttachInfo.mVisibleInsets;
@@ -7090,13 +7103,13 @@
* Start a drag resizing which will inform all listeners that a window resize is taking place.
*/
private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets) {
+ Rect stableInsets, int resizeMode) {
if (!mDragResizing) {
mDragResizing = true;
synchronized (mWindowCallbacks) {
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
- systemInsets, stableInsets);
+ systemInsets, stableInsets, resizeMode);
}
}
mFullRedrawNeeded = true;
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index d2bfca7..b2dc1e9 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -26,6 +26,11 @@
* @hide
*/
public interface WindowCallbacks {
+
+ public static final int RESIZE_MODE_INVALID = -1;
+ public static final int RESIZE_MODE_FREEFORM = 0;
+ public static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
+
/**
* Called by the system when the window got changed by the user, before the layouter got called.
* It also gets called when the insets changed, or when the window switched between a fullscreen
@@ -51,7 +56,7 @@
* @param stableInsets The stable insets for the window.
*/
void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets);
+ Rect stableInsets, int resizeMode);
/**
* Called when a drag resize ends.
@@ -69,4 +74,13 @@
* @param reportNextDraw Whether it should report when the requested draw finishes.
*/
void onRequestDraw(boolean reportNextDraw);
+
+ /**
+ * Called after all the content has drawn and the callback now has the ability to draw something
+ * on top of everything. Call {@link ViewRootImpl#requestInvalidateRootRenderNode} when this
+ * content needs to be redrawn.
+ *
+ * @param canvas The canvas to draw on.
+ */
+ void onPostDraw(DisplayListCanvas canvas);
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 655c9b3..7f44bac 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -59,4 +59,8 @@
boolean touchExplorationEnabled);
IBinder getWindowToken(int windowId, int userId);
+
+ void enableAccessibilityService(in ComponentName service, int userId);
+
+ void disableAccessibilityService(in ComponentName service, int userId);
}
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index c0dce22..7bd64e5 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -26,6 +26,7 @@
import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
import java.util.HashSet;
@@ -72,15 +73,17 @@
public void register(Context context, Looper thread, UserHandle user,
boolean externalStorage) {
+ register(context, user, externalStorage,
+ (thread == null) ? BackgroundThread.getHandler() : new Handler(thread));
+ }
+
+ public void register(Context context, UserHandle user,
+ boolean externalStorage, Handler handler) {
if (mRegisteredContext != null) {
throw new IllegalStateException("Already registered");
}
mRegisteredContext = context;
- if (thread == null) {
- mRegisteredHandler = BackgroundThread.getHandler();
- } else {
- mRegisteredHandler = new Handler(thread);
- }
+ mRegisteredHandler = Preconditions.checkNotNull(handler);
if (user != null) {
context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 6931193..738aaca 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -16,6 +16,8 @@
package com.android.internal.policy;
+import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -69,6 +71,7 @@
private ColorDrawable mNavigationBarColor;
private boolean mOldFullscreen;
private boolean mFullscreen;
+ private final int mResizeMode;
private final Rect mOldSystemInsets = new Rect();
private final Rect mOldStableInsets = new Rect();
private final Rect mSystemInsets = new Rect();
@@ -77,7 +80,7 @@
public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
- boolean fullscreen, Rect systemInsets, Rect stableInsets) {
+ boolean fullscreen, Rect systemInsets, Rect stableInsets, int resizeMode) {
setName("ResizeFrame");
mRenderer = renderer;
@@ -98,6 +101,7 @@
mStableInsets.set(stableInsets);
mOldSystemInsets.set(systemInsets);
mOldStableInsets.set(stableInsets);
+ mResizeMode = resizeMode;
synchronized (this) {
redrawLocked(initialBounds, fullscreen, mSystemInsets, mStableInsets);
}
@@ -266,11 +270,16 @@
mLastXOffset = xOffset;
mLastYOffset = yOffset;
- mRenderer.setContentDrawBounds(
- mLastXOffset,
- mLastYOffset,
- mLastXOffset + mLastContentWidth,
- mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+ // Only clip the content to the bounds if we are not fullscreen. In the other case, we
+ // actually need to draw outside these.
+ if (mResizeMode == RESIZE_MODE_FREEFORM) {
+ mRenderer.setContentDrawBounds(
+ mLastXOffset,
+ mLastYOffset,
+ mLastXOffset + mLastContentWidth,
+ mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+ }
+
// If this was the first call and redrawLocked got already called prior
// to us, we should re-issue a redrawLocked now.
return firstCall
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index bdf2a21..9904893 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -39,8 +39,11 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.RemoteException;
@@ -49,6 +52,7 @@
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
+import android.view.DisplayListCanvas;
import android.view.Gravity;
import android.view.InputQueue;
import android.view.KeyEvent;
@@ -88,6 +92,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -211,6 +216,11 @@
private boolean mApplyFloatingVerticalInsets = false;
private boolean mApplyFloatingHorizontalInsets = false;
+ private int mResizeMode = RESIZE_MODE_INVALID;
+ private final int mResizeShadowSize;
+ private final Paint mVerticalResizeShadowPaint = new Paint();
+ private final Paint mHorizontalResizeShadowPaint = new Paint();
+
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
super(context);
@@ -233,6 +243,10 @@
setWindow(window);
updateLogTag(params);
+
+ mResizeShadowSize = context.getResources().getDimensionPixelSize(
+ R.dimen.resize_shadow_size);
+ initResizingPaints();
}
void setBackgroundFallback(int resId) {
@@ -699,6 +713,10 @@
// our shadow elevation.
updateElevation();
mAllowUpdateElevation = true;
+
+ if (changed && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER) {
+ getViewRootImpl().requestInvalidateRootRenderNode();
+ }
}
@Override
@@ -1907,7 +1925,7 @@
@Override
public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets) {
+ Rect stableInsets, int resizeMode) {
if (mWindow.isDestroyed()) {
// If the owner's window is gone, we should not be able to come here anymore.
releaseThreadedRenderer();
@@ -1923,7 +1941,7 @@
initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
- stableInsets);
+ stableInsets, resizeMode);
// Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
// If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -1932,12 +1950,16 @@
updateColorViews(null /* insets */, false);
}
+ mResizeMode = resizeMode;
+ getViewRootImpl().requestInvalidateRootRenderNode();
}
@Override
public void onWindowDragResizeEnd() {
releaseThreadedRenderer();
updateColorViews(null /* insets */, false);
+ mResizeMode = RESIZE_MODE_INVALID;
+ getViewRootImpl().requestInvalidateRootRenderNode();
}
@Override
@@ -1960,6 +1982,41 @@
}
}
+ @Override
+ public void onPostDraw(DisplayListCanvas canvas) {
+ drawResizingShadowIfNeeded(canvas);
+ }
+
+ private void initResizingPaints() {
+ final int startColor = mContext.getResources().getColor(
+ R.color.resize_shadow_start_color, null);
+ final int endColor = mContext.getResources().getColor(
+ R.color.resize_shadow_end_color, null);
+ final int middleColor = (startColor + endColor) / 2;
+ mHorizontalResizeShadowPaint.setShader(new LinearGradient(
+ 0, 0, 0, mResizeShadowSize, new int[] { startColor, middleColor, endColor },
+ new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
+ mVerticalResizeShadowPaint.setShader(new LinearGradient(
+ 0, 0, mResizeShadowSize, 0, new int[] { startColor, middleColor, endColor },
+ new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
+ }
+
+ private void drawResizingShadowIfNeeded(DisplayListCanvas canvas) {
+ if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
+ || mWindow.isTranslucent()
+ || (mWindow.getAttributes().flags & FLAG_SHOW_WALLPAPER) != 0) {
+ return;
+ }
+ canvas.save();
+ canvas.translate(0, getHeight() - mFrameOffsets.bottom);
+ canvas.drawRect(0, 0, getWidth(), mResizeShadowSize, mHorizontalResizeShadowPaint);
+ canvas.restore();
+ canvas.save();
+ canvas.translate(getWidth() - mFrameOffsets.right, 0);
+ canvas.drawRect(0, 0, mResizeShadowSize, getHeight(), mVerticalResizeShadowPaint);
+ canvas.restore();
+ }
+
/** Release the renderer thread which is usually done when the user stops resizing. */
private void releaseThreadedRenderer() {
if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7637eec..794a6d6 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -157,6 +157,7 @@
InputQueue.Callback mTakeInputQueueCallback;
boolean mIsFloating;
+ private boolean mIsTranslucent;
private LayoutInflater mLayoutInflater;
@@ -490,6 +491,10 @@
return mIsFloating;
}
+ public boolean isTranslucent() {
+ return mIsTranslucent;
+ }
+
/**
* Return a LayoutInflater instance that can be used to inflate XML view layout
* resources for use in this Window.
@@ -2400,6 +2405,8 @@
requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
}
+ mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
+
final Context context = getContext();
final int targetSdk = context.getApplicationInfo().targetSdkVersion;
final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index b243cac..9e5c238 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -88,6 +88,11 @@
*/
void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
+ /**
+ * Notifies the status bar that an app transition is done.
+ */
+ void appTransitionFinished();
+
void showAssistDisclosure();
void startAssist(in Bundle args);
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
index 4a196f8..5f390be 100644
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -1,27 +1,20 @@
package com.android.internal.util;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.os.Build;
import android.os.SystemProperties;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
import android.view.ViewRootImpl;
-import com.android.internal.R;
-
/**
* @hide
*/
public class ScreenShapeHelper {
- private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish");
-
/**
* Return the bottom pixel window outset of a window given its style attributes.
* @return An outset dimension in pixels or 0 if no outset should be applied.
*/
public static int getWindowOutsetBottomPx(Resources resources) {
- if (IS_EMULATOR) {
+ if (Build.IS_EMULATOR) {
return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0);
} else {
return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom);
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 1ead618..528541d 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -723,6 +723,7 @@
// Make sure that the recycled bitmap has the correct alpha type.
mRecycledBitmap->setAlphaType(bitmap->alphaType());
+ bitmap->notifyPixelsChanged();
bitmap->lockPixels();
mNeedsCopy = false;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 60f05448..8abb7e2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -706,7 +706,9 @@
android:description="@string/permgroupdesc_phone"
android:priority="500" />
- <!-- Allows read only access to phone state.
+ <!-- Allows read only access to phone state, including the phone number of the device,
+ current cellular network information, the status of any ongoing calls, and a list of any
+ {@link android.telecom.PhoneAccount}s registered on the device.
<p class="note"><strong>Note:</strong> If <em>both</em> your <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
minSdkVersion}</a> and <a
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 48aa440..bddd225 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -180,4 +180,7 @@
<!-- Status bar color for semi transparent mode. -->
<color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
+
+ <color name="resize_shadow_start_color">#2a000000</color>
+ <color name="resize_shadow_end_color">#00000000</color>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9b7b1d4..71d9a1f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -452,4 +452,6 @@
<item type="dimen" name="aerr_padding_list_top">15dp</item>
<item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
+
+ <dimen name="resize_shadow_size">5dp</dimen>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7426ddf..3f46768 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1512,6 +1512,9 @@
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="fraction" name="thumbnail_fullscreen_scale" />
+ <java-symbol type="dimen" name="resize_shadow_size" />
+ <java-symbol type="color" name="resize_shadow_start_color" />
+ <java-symbol type="color" name="resize_shadow_end_color" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 06b712e..ea4f4eb 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -506,6 +506,22 @@
renderer.renderGlop(state, glop);
}
+void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
+ SkPaint paint;
+ paint.setColor(op.color);
+ paint.setXfermodeMode(op.mode);
+
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshUnitQuad()
+ .setFillPaint(paint, state.alpha)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewMapUnitToRect(state.computedState.clipState->rect)
+ .build();
+ renderer.renderGlop(state, glop);
+}
+
void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
renderer.renderFunctor(op, state);
}
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index fae8e48..0ebb886 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -572,6 +572,12 @@
deferOvalOp(*resolvedOp);
}
+void FrameBuilder::deferColorOp(const ColorOp& op) {
+ BakedOpState* bakedState = tryBakeUnboundedOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
+}
+
void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
if (!bakedState) return; // quick rejected
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 96a57b6..64c604a 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -90,6 +90,7 @@
UNMERGEABLE_OP_FN(ArcOp) \
UNMERGEABLE_OP_FN(BitmapMeshOp) \
UNMERGEABLE_OP_FN(BitmapRectOp) \
+ UNMERGEABLE_OP_FN(ColorOp) \
UNMERGEABLE_OP_FN(FunctorOp) \
UNMERGEABLE_OP_FN(LinesOp) \
UNMERGEABLE_OP_FN(OvalOp) \
@@ -256,6 +257,16 @@
const float* radius;
};
+struct ColorOp : RecordedOp {
+ // Note: unbounded op that will fillclip, so no bounds/matrix needed
+ ColorOp(const ClipBase* localClip, int color, SkXfermode::Mode mode)
+ : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr)
+ , color(color)
+ , mode(mode) {}
+ const int color;
+ const SkXfermode::Mode mode;
+};
+
struct FunctorOp : RecordedOp {
// Note: undefined record-time bounds, since this op fills the clip
// TODO: explicitly define bounds
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4eeadb7..f43dade 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -234,10 +234,10 @@
// android/graphics/Canvas draw operations
// ----------------------------------------------------------------------------
void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
- SkPaint paint;
- paint.setColor(color);
- paint.setXfermodeMode(mode);
- drawPaint(paint);
+ addOp(alloc().create_trivial<ColorOp>(
+ getRecordedClip(),
+ color,
+ mode));
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 1eb4fa0..acb88e2 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -191,13 +191,16 @@
const SkPaint* paint) override;
// Text
- virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int glyphCount,
- const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
- float boundsRight, float boundsBottom, float totalAdvance) override;
- virtual void drawGlyphsOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) override;
virtual bool drawTextAbsolutePos() const override { return false; }
+protected:
+ virtual void drawGlyphs(const uint16_t* text, const float* positions, int count,
+ const SkPaint& paint, float x, float y,
+ float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+ float totalAdvance) override;
+ virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ float hOffset, float vOffset, const SkPaint& paint) override;
+
private:
const ClipBase* getRecordedClip() {
return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index b1ecb71..5d24fa0 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -147,13 +147,6 @@
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) override;
- virtual void drawGlyphs(const uint16_t* text, const float* positions, int count,
- const SkPaint& paint, float x, float y,
- float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) override;
- virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) override;
-
virtual bool drawTextAbsolutePos() const override { return true; }
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
@@ -169,6 +162,14 @@
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
virtual void callDrawGLFunction(Functor* functor) override;
+protected:
+ virtual void drawGlyphs(const uint16_t* text, const float* positions, int count,
+ const SkPaint& paint, float x, float y,
+ float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+ float totalAdvance) override;
+ virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ float hOffset, float vOffset, const SkPaint& paint) override;
+
private:
struct SaveRec {
int saveCount;
@@ -761,14 +762,8 @@
const SkPaint& paint, float x, float y,
float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
float totalAdvance) {
- // Set align to left for drawing, as we don't want individual
- // glyphs centered or right-aligned; the offset above takes
- // care of all alignment.
- SkPaint paintCopy(paint);
- paintCopy.setTextAlign(SkPaint::kLeft_Align);
-
static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
- mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
+ mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paint);
drawTextDecorations(x, y, totalAdvance, paint);
}
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 8c3eea3..7bfa15a 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -166,6 +166,11 @@
bounds.offset(x, y);
}
+ // Set align to left for drawing, as we don't want individual
+ // glyphs centered or right-aligned; the offset above takes
+ // care of all alignment.
+ paint.setTextAlign(Paint::kLeft_Align);
+
DrawTextFunctor f(layout, this, glyphs.get(), pos.get(),
paint, x, y, bounds, layout.getAdvance());
MinikinUtils::forFontRun(layout, &paint, f);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index dc669f0..5dbda43 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -53,6 +53,7 @@
} // namespace SaveFlags
namespace uirenderer {
+class SkiaCanvasProxy;
namespace VectorDrawable {
class Tree;
};
@@ -205,19 +206,6 @@
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) = 0;
- // Text
- /**
- * drawText: count is of glyphs
- * totalAdvance: used to define width of text decorations (underlines, strikethroughs).
- */
- virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int count,
- const SkPaint& paint, float x, float y,
- float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) = 0;
- /** drawTextOnPath: count is of glyphs */
- virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
- float hOffset, float vOffset, const SkPaint& paint) = 0;
-
/**
* Specifies if the positions passed to ::drawText are absolute or relative
* to the (x,y) value provided.
@@ -244,6 +232,22 @@
protected:
void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
+
+ /**
+ * drawText: count is of glyphs
+ * totalAdvance: used to define width of text decorations (underlines, strikethroughs).
+ */
+ virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int count,
+ const SkPaint& paint, float x, float y,
+ float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+ float totalAdvance) = 0;
+ /** drawTextOnPath: count is of glyphs */
+ virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ float hOffset, float vOffset, const SkPaint& paint) = 0;
+
+ friend class DrawTextFunctor;
+ friend class DrawTextOnPathFunctor;
+ friend class uirenderer::SkiaCanvasProxy;
};
}; // namespace android
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 69c321c..9599c30 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -30,6 +30,7 @@
public:
Paint();
Paint(const Paint& paint);
+ Paint(const SkPaint& paint);
~Paint();
Paint& operator=(const Paint& other);
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 1172a0e..b27672c 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -29,6 +29,11 @@
mHyphenEdit(paint.mHyphenEdit) {
}
+Paint::Paint(const SkPaint& paint) : SkPaint(paint),
+ mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
+ mFontVariant(VARIANT_DEFAULT) {
+}
+
Paint::~Paint() {
}
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index a4aee61..059e9ae 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -16,6 +16,7 @@
#include "TestUtils.h"
+#include "hwui/Paint.h"
#include "DeferredLayerUpdater.h"
#include "LayerRenderer.h"
@@ -41,17 +42,20 @@
sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
- std::function<void(Matrix4*)> transformSetupCallback) {
+ const SkMatrix& transform) {
+ Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
+
+ sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
+ layerUpdater->setSize(width, height);
+ layerUpdater->setTransform(&transform);
+
+ // updateLayer so it's ready to draw
bool isOpaque = true;
bool forceFilter = true;
GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
-
- Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
- renderTarget, Matrix4::identity().data);
- transformSetupCallback(&(layer->getTransform()));
+ renderTarget, Matrix4::identity().data);
- sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
return layerUpdater;
}
@@ -87,50 +91,17 @@
*outTotalAdvance = totalAdvance;
}
-void TestUtils::drawUtf8ToCanvas(TestCanvas* canvas, const char* text,
+
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
const SkPaint& paint, float x, float y) {
- // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
- LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
- "must use glyph encoding");
- SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
- SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
-
- std::vector<glyph_t> glyphs;
- std::vector<float> positions;
- float totalAdvance;
- Rect bounds;
- layoutTextUnscaled(paint, text, &glyphs, &positions, &totalAdvance, &bounds);
-
- // apply alignment via x parameter (which JNI layer would have done)
- if (paint.getTextAlign() == SkPaint::kCenter_Align) {
- x -= totalAdvance / 2;
- } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
- x -= totalAdvance;
- }
-
- bounds.translate(x, y);
-
- // Force left alignment, since alignment offset is already baked in
- SkPaint alignPaintCopy(paint);
- alignPaintCopy.setTextAlign(SkPaint::kLeft_Align);
- canvas->drawGlyphs(glyphs.data(), positions.data(), glyphs.size(), alignPaintCopy, x, y,
- bounds.left, bounds.top, bounds.right, bounds.bottom, totalAdvance);
+ auto utf16 = asciiToUtf16(text);
+ canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, 0, paint, nullptr);
}
-void TestUtils::drawUtf8ToCanvas(TestCanvas* canvas, const char* text,
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
const SkPaint& paint, const SkPath& path) {
- // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
- LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
- "must use glyph encoding");
- SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
- SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
-
- std::vector<glyph_t> glyphs;
- while (*text != '\0') {
- SkUnichar unichar = SkUTF8_NextUnichar(&text);
- glyphs.push_back(autoCache.getCache()->unicharToGlyph(unichar));
- }
- canvas->drawGlyphsOnPath(glyphs.data(), glyphs.size(), path, 0, 0, paint);
+ auto utf16 = asciiToUtf16(text);
+ canvas->drawTextOnPath(utf16.get(), strlen(text), 0, path, 0, 0, paint, nullptr);
}
void TestUtils::TestTask::run() {
@@ -143,12 +114,13 @@
renderState.onGLContextDestroyed();
}
-std::unique_ptr<uint16_t[]> TestUtils::utf8ToUtf16(const char* str) {
- const size_t strLen = strlen(str);
- const ssize_t utf16Len = utf8_to_utf16_length((uint8_t*) str, strLen);
- std::unique_ptr<uint16_t[]> dst(new uint16_t[utf16Len + 1]);
- utf8_to_utf16((uint8_t*) str, strLen, (char16_t*) dst.get());
- return dst;
+std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) {
+ const int length = strlen(str);
+ std::unique_ptr<uint16_t[]> utf16(new uint16_t[length]);
+ for (int i = 0; i < length; i++) {
+ utf16.get()[i] = str[i];
+ }
+ return utf16;
}
} /* namespace uirenderer */
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index a5e7a5f..2d1e2e9 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -122,7 +122,7 @@
static sp<DeferredLayerUpdater> createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
- std::function<void(Matrix4*)> transformSetupCallback);
+ const SkMatrix& transform);
template<class CanvasType>
static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
@@ -207,13 +207,13 @@
std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
float* outTotalAdvance, Rect* outBounds);
- static void drawUtf8ToCanvas(TestCanvas* canvas, const char* text,
+ static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
const SkPaint& paint, float x, float y);
- static void drawUtf8ToCanvas(TestCanvas* canvas, const char* text,
+ static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
const SkPaint& paint, const SkPath& path);
- static std::unique_ptr<uint16_t[]> utf8ToUtf16(const char* str);
+ static std::unique_ptr<uint16_t[]> asciiToUtf16(const char* str);
private:
static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index 52039ef..63c067b 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -42,7 +42,7 @@
}
void doFrame(int frameNr) override {
- std::unique_ptr<uint16_t[]> text = TestUtils::utf8ToUtf16(
+ std::unique_ptr<uint16_t[]> text = TestUtils::asciiToUtf16(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
ssize_t textLength = 26 * 2;
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 0aabfb1..dca56d4 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -344,8 +344,9 @@
EXPECT_TRUE(stroke.contains(fill));
EXPECT_FALSE(fill.contains(stroke));
+ // outset by half the stroke width
Rect outsetFill(fill);
- outsetFill.outset(10);
+ outsetFill.outset(5);
EXPECT_EQ(stroke, outsetFill);
}
};
@@ -386,9 +387,7 @@
};
auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- [](Matrix4* transform) {
- transform->loadTranslate(5, 5, 0);
- });
+ SkMatrix::MakeTrans(5, 5));
auto node = TestUtils::createNode(0, 0, 200, 200,
[&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
@@ -428,7 +427,31 @@
EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
}
-RENDERTHREAD_TEST(FrameBuilder, renderNode) {
+RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
+ class ColorTestRenderer : public TestRendererBase {
+ public:
+ void onColorOp(const ColorOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
+ << "Color op should be expanded to bounds of surrounding";
+ }
+ };
+
+ auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setClipToBounds(false);
+ canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
+ });
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ TestUtils::createSyncedNodeList(unclippedColorView),
+ sLightGeometry, Caches::getInstance());
+ ColorTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
+}
+
+TEST(FrameBuilder, renderNode) {
class RenderNodeTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index ca72673..1c240db 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -226,9 +226,9 @@
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
auto op = *(dl->getOps()[0]);
- EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(RecordedOpId::ColorOp, op.opId);
EXPECT_EQ(nullptr, op.localClip);
- EXPECT_TRUE(op.unmappedBounds.contains(Rect(200, 200))) << "Expect recording/clip bounds";
+ EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds";
}
TEST(RecordingCanvas, backgroundAndImage) {
@@ -570,36 +570,30 @@
TEST(RecordingCanvas, refPaint) {
SkPaint paint;
- paint.setAntiAlias(true);
- paint.setTextSize(20);
- paint.setTextAlign(SkPaint::kLeft_Align);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
paint.setColor(SK_ColorBLUE);
- // first three should use same paint
+ // first two should use same paint
canvas.drawRect(0, 0, 200, 10, paint);
SkPaint paintCopy(paint);
canvas.drawRect(0, 10, 200, 20, paintCopy);
- TestUtils::drawUtf8ToCanvas(&canvas, "helloworld", paint, 50, 25);
// only here do we use different paint ptr
paint.setColor(SK_ColorRED);
canvas.drawRect(0, 20, 200, 30, paint);
});
auto ops = dl->getOps();
- ASSERT_EQ(4u, ops.size());
+ ASSERT_EQ(3u, ops.size());
- // first three are the same
+ // first two are the same
EXPECT_NE(nullptr, ops[0]->paint);
EXPECT_NE(&paint, ops[0]->paint);
EXPECT_EQ(ops[0]->paint, ops[1]->paint);
- EXPECT_EQ(ops[0]->paint, ops[2]->paint);
// last is different, but still copied / non-null
- EXPECT_NE(nullptr, ops[3]->paint);
- EXPECT_NE(ops[0]->paint, ops[3]->paint);
- EXPECT_NE(&paint, ops[3]->paint);
+ EXPECT_NE(nullptr, ops[2]->paint);
+ EXPECT_NE(ops[0]->paint, ops[2]->paint);
+ EXPECT_NE(&paint, ops[2]->paint);
}
TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
@@ -647,7 +641,7 @@
paint.setAntiAlias(true);
paint.setTextSize(20);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- std::unique_ptr<uint16_t[]> dst = TestUtils::utf8ToUtf16("HELLO");
+ std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL);
});
@@ -671,7 +665,7 @@
paint.setAntiAlias(true);
paint.setTextSize(20);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- std::unique_ptr<uint16_t[]> dst = TestUtils::utf8ToUtf16("HELLO");
+ std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL);
});
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 7c9591d..acf94f4c 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -1039,6 +1039,15 @@
}
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.TV_INPUT_HIDDEN_INPUTS, builder.toString(), userId);
+
+ // Notify of the TvInputInfo changes.
+ TvInputManager tm = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+ for (String inputId : hiddenInputIds) {
+ TvInputInfo info = tm.getTvInputInfo(inputId);
+ if (info != null) {
+ tm.updateTvInputInfo(info);
+ }
+ }
}
/**
@@ -1069,6 +1078,15 @@
}
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.TV_INPUT_CUSTOM_LABELS, builder.toString(), userId);
+
+ // Notify of the TvInputInfo changes.
+ TvInputManager tm = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+ for (String inputId : customLabels.keySet()) {
+ TvInputInfo info = tm.getTvInputInfo(inputId);
+ if (info != null) {
+ tm.updateTvInputInfo(info);
+ }
+ }
}
private static void ensureValidField(String value) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 2af6c46..bed8b29 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -381,7 +381,7 @@
}
// Open the Close drawer if it is closed and we're at the top of a root.
- if (size == 1) {
+ if (size <= 1) {
mDrawer.setOpen(true);
// Remember so we don't just close it again if back is pressed again.
mDrawerLastFiddled = System.currentTimeMillis();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 062f2d1..4acf85e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -1049,7 +1049,7 @@
}
// Can't copy folders to downloads, because we don't show folders there.
- if (!root.isDownloads()) {
+ if (root.isDownloads()) {
for (DocumentInfo docs : files) {
if (docs.isDirectory()) {
return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
index b53e165..748da00 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
@@ -158,11 +158,11 @@
}
/**
- * Starts the service for a move operation.
+ * Starts the service for a delete operation.
*
* @param jobId A unique jobid for this job.
* Use {@link #createJobId} if you don't have one handy.
- * @param srcDocs A list of src files to copy.
+ * @param srcDocs A list of src files to delete.
* @param srcParent Parent of all the source documents.
* @return Id of the job.
*/
@@ -184,7 +184,7 @@
*
* @param jobId A unique jobid for this job.
* Use {@link #createJobId} if you don't have one handy.
- * @param srcDocs A list of src files to copy.
+ * @param srcDocs A list of src files for an operation.
* @return Id of the job.
*/
public static Intent createBaseIntent(
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index 5089512..098d5a2 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -108,7 +108,7 @@
<string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-картанын PUK-кодун ачуу кыйрады!"</string>
<string name="kg_pin_accepted" msgid="1448241673570020097">"Код кабыл алынды!"</string>
<string name="keyguard_carrier_default" msgid="8700650403054042153">"Байланыш жок."</string>
- <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Киргизүү ыкмасын которуу"</string>
+ <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Киргизүү ыкмасын өзгөртүү"</string>
<string name="airplane_mode" msgid="3122107900897202805">"Учак режими"</string>
<string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Түзмөк кайра күйгүзүлгөндөн кийин графикалык ачкыч талап кылынат"</string>
<string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Түзмөк кайра күйгүзүлгөндөн кийин PIN код талап кылынат"</string>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 81666fe..a73dcb6 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -108,7 +108,7 @@
<string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM卡PUK码操作失败!"</string>
<string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string>
<string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
- <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"输入法切换按钮。"</string>
+ <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"切换输入法"</string>
<string name="airplane_mode" msgid="3122107900897202805">"飞行模式"</string>
<string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"重启设备后需要绘制解锁图案"</string>
<string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"重启设备后需要输入 PIN 码"</string>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index c8478f2..0224c6c 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Herbegin"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met drukker nie"</string>
<string name="reason_unknown" msgid="5507940196503246139">"onbekend"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nie beskikbaar nie"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Gebruik <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Jou dokument kan dalk deur een of meer bedieners op pad na die drukker gaan."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Jammer, dit het nie gewerk nie. Probeer weer."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Herprobeer"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Hierdie drukker is nie op die oomblik beskikbaar nie."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan nie voorskou wys nie"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Berei tans voorskou voor …"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index d4426cc..98255d4 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string>
<string name="reason_unknown" msgid="5507940196503246139">"አይታወቅም"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – አይገኝም"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ይጠቀሙ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ሰነድዎ ወደ አታሚው በሚሄድበት ወቅት በአንድ ወይም ከዚያ በላይ አገልጋዮች ውስጥ ሊያልፍ ይችላል።"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ይቅርታ፣ ያ አልሰራም። እንደገና ይሞክሩ።"</string>
<string name="print_error_retry" msgid="1426421728784259538">"እንደገና ይሞክሩ"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"አታሚው አሁን አይገኝም።"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"ቅድመ ዕይታን ማሳየት አይቻልም"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"ቅድመ እይታን በማዘጋጀት ላይ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 2e1b6d0..5f0255c 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -84,7 +84,6 @@
<string name="restart" msgid="2472034227037808749">"إعادة تشغيل"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"لا يوجد اتصال بالطابعة"</string>
<string name="reason_unknown" msgid="5507940196503246139">"غير معروف"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – غير متاحة"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"هل تريد استخدام <xliff:g id="SERVICE">%1$s</xliff:g>؟"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"من الممكن أن يمر المستند عبر خادم أو أكثر أثناء إرساله إلى الطابعة."</string>
<string-array name="color_mode_labels">
@@ -104,5 +103,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"عذرًا، هذا لا يعمل. أعد المحاولة."</string>
<string name="print_error_retry" msgid="1426421728784259538">"إعادة المحاولة"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"الطابعة ليست متوفرة في الوقت الحالي."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"يتعذر عرض المعاينة."</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"جارٍ تحضير المعاينة…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index 5490b84..b5dfaf8 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Yenidən başlat"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Printerə heç bir bağlantı yoxdur"</string>
<string name="reason_unknown" msgid="5507940196503246139">"naməlum"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>– əlçatmaz"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> xidmətindən istifadə edilsin?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Sənədiniz printerə qədər bir və ya daha çox server vasitəsilə keçə bilər."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Üzr istəyirik, alınmadı. Yenidən cəhd edin."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Yenidən yoxla"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Bu printer hazırda əlçatan deyil."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Önizləmə göstərilə bilmir"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Önizləməyə hazırlıq gedir..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index 0574dae..2ac8002 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -81,7 +81,6 @@
<string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze sa štampačem"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nepoznato"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nedostupan"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite li da koristite <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument može da prođe kroz jedan ili više servera na putu do štampača."</string>
<string-array name="color_mode_labels">
@@ -101,5 +100,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Žao nam je, ovo nije uspelo. Pokušajte ponovo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovo"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ovaj štampač trenutno nije dostupan."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Nije uspeo prikaz pregleda"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-be-rBY/strings.xml b/packages/PrintSpooler/res/values-be-rBY/strings.xml
index b581045..13d573e 100644
--- a/packages/PrintSpooler/res/values-be-rBY/strings.xml
+++ b/packages/PrintSpooler/res/values-be-rBY/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Перазапусціць"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Няма падлучэння да прынтара"</string>
<string name="reason_unknown" msgid="5507940196503246139">"невядома"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недаступна"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Выкарыстоўваць службу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Ваш дакумент можа прайсці праз адзін ці больш сервераў перад тым, як будзе надрукаваны."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"На жаль, не атрымалася. Паспрабуйце яшчэ раз."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Паўтарыць спробу"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Гэты прынтар зараз недаступны."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Папярэдні прагляд немагчымы"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Падрыхтоўка папярэдняга прагляду..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 88af8e4..73c51e9 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Рестартиране"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Няма връзка с принтера"</string>
<string name="reason_unknown" msgid="5507940196503246139">"няма данни"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – не е налице"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Да се използва ли „<xliff:g id="SERVICE">%1$s</xliff:g>“?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"По пътя към принтера документът ви може да премине през един или повече сървъри."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"За съжаление това не проработи. Опитайте отново."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Нов опит"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"В момента този принтер не е налице."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Визуализацията не може да се покаже"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Визуализацията се подготвя…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index c61ef74..25b4660 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"পুনর্সূচনা"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"মুদ্রকে কোনো সংযোগ নেই"</string>
<string name="reason_unknown" msgid="5507940196503246139">"অজানা"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – অনুপলব্ধ"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ব্যবহার করবেন?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"আপনার দস্তাবেজ মুদ্রকে যাওয়ার সময় এক বা একাধিক সার্ভারের মাধ্যমে পাস হতে পারে।"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"দুঃখিত, এটি কাজ করেনি৷ আবার চেষ্টা করুন৷"</string>
<string name="print_error_retry" msgid="1426421728784259538">"পুনরায় চেষ্টা করুন"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"এই মূহুর্তে প্রিন্টার উপলব্ধ নয়।"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"পূর্বরূপ প্রদর্শন করা যাবে না"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"পূর্বরূপ প্রস্তুত করছে..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
index 7465c3c..9a17707 100644
--- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -81,7 +81,6 @@
<string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nema konekcije sa štampačem"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nepoznat"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nedostupan"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Zaista želite koristiti uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Moguće je da dokument prije štampanja prođe kroz jedan ili više servera."</string>
<string-array name="color_mode_labels">
@@ -101,5 +100,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Nažalost, nije uspjelo. Pokušajte ponovo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Ponovi"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Štampač trenutno nije dostupan."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Pregled se ne može prikazati"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index 482100a..a1df406 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Reinicia"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"No hi ha connexió amb la impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconegut"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: no disponible"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Vols fer servir <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"És possible que el document passi com a mínim per un servidor abans d\'imprimir-se."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionat. Torna-ho a provar."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Torna-ho a provar"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ara mateix, aquesta impressora no està disponible."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"La previsualització no es pot mostrar"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"S\'està preparant la previsualització..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index a4c412c..55fb21b 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Restartovat"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nelze se připojit k tiskárně"</string>
<string name="reason_unknown" msgid="5507940196503246139">"neznámé"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – není k dispozici"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Použít službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument může cestou do tiskárny projít jedním i více servery."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Litujeme, nepodařilo se. Zkuste to znovu."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Opakovat"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Tiskárna aktuálně není k dispozici."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Náhled nelze zobrazit"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Příprava náhledu…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 9ee252167..49417bd 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Genstart"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse til printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ukendt"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ikke tilgængelig"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Vil du bruge <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dit dokument passerer muligvis gennem én eller flere servere på vej til printeren."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Det virkede desværre ikke. Prøv igen."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Prøv igen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Denne printer er i øjeblikket ikke tilgængelig."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Eksempelvisning kan ikke vises"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Eksempelvisning forberedes..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index ef451b7..cb7aeee 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Neu starten"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Keine Verbindung zum Drucker"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unbekannt"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nicht verfügbar"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> verwenden?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dein Dokument passiert bei der Übermittlung an den Drucker möglicherweise einen oder mehrere Server."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuche es erneut."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Erneut versuchen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Dieser Drucker ist momentan nicht verfügbar."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Vorschau kann nicht angezeigt werden"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Vorschau wird vorbereitet…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 9be81c1..4441ea2 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Επανεκκίνηση"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Δεν υπάρχει σύνδεση με εκτυπωτή"</string>
<string name="reason_unknown" msgid="5507940196503246139">"άγνωστο"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – μη διαθέσιμο"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Να χρησιμοποιηθεί η υπηρεσία <xliff:g id="SERVICE">%1$s</xliff:g>;"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Το έγγραφό σας μπορεί να περάσει από έναν ή περισσότερους διακομιστές κατά τη μετάβαση στον εκτυπωτή."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Δυστυχώς, αυτό δεν λειτούργησε. Δοκιμάστε ξανά."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Επανάληψη"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Αυτός ο εκτυπωτής δεν είναι διαθέσιμος αυτήν τη στιγμή."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Αδυναμία προβολής προεπισκόπησης"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Προετοιμασία προεπισκόπησης…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index 8b58011..f8b6265 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Restart"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Use <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Your document may pass through one or more servers on its way to the printer."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Sorry, that didn\'t work. Try again."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"This printer isn\'t available right now."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Can\'t display preview"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparing preview…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 8b58011..f8b6265 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Restart"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Use <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Your document may pass through one or more servers on its way to the printer."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Sorry, that didn\'t work. Try again."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"This printer isn\'t available right now."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Can\'t display preview"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparing preview…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 8b58011..f8b6265 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Restart"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Use <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Your document may pass through one or more servers on its way to the printer."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Sorry, that didn\'t work. Try again."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"This printer isn\'t available right now."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Can\'t display preview"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparing preview…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8fa6094..8d55597 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora."</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconocido"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: no disponible"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"¿Deseas usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Es posible que el documento pase por uno o varios servidores antes de imprimirse."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"No funcionó. Vuelve a intentarlo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Volver a intentar"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora no está disponible en este momento."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"No se puede mostrar la vista previa"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparando vista previa…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index dba0491..7d08a0e 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Volver a empezar"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconocido"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – no disponible"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"¿Usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Es posible que el documento pase por uno o varios servidores antes de imprimirse."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionado. Prueba de nuevo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora no está disponible en este momento."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"No se puede mostrar la vista previa"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparando vista previa…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 6dde083..09da3e0 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Taaskäivita"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Printeriühendus puudub"</string>
<string name="reason_unknown" msgid="5507940196503246139">"teadmata"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – pole saadaval"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Kas soovite kasutada teenust <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Printerini jõudmiseks võib dokument läbida ühe või mitu serverit."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Kahjuks see ei toiminud. Proovige uuesti."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Proovi uuesti"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"See printer ei ole praegu saadaval."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Eelvaadet ei õnnestu kuvada"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Eelvaate ettevalmistamine ..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 858444b..6b760b4 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Berrabiarazi"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Inprimagailua ez dago konektatuta"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ezezaguna"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: ez dago erabilgarri"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> erabili nahi duzu?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Baliteke dokumentuak zerbitzari batean edo gehiagotan zehar igarotzea inprimagailurako bidean."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Horrek ez du funtzionatu. Saiatu berriro."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Saiatu berriro"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Une honetan inprimagailua ez dago erabilgarri."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Ezin da bistaratu aurrebista"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Aurrebista prestatzen…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 7c69c27..fa105d5 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"راهاندازی مجدد"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"اتصال با چاپگر برقرار نیست"</string>
<string name="reason_unknown" msgid="5507940196503246139">"نامعلوم"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - در دسترس نیست"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"از <xliff:g id="SERVICE">%1$s</xliff:g> استفاده شود؟"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ممکن است سندتان برای رسیدن به چاپگر از یک یا چند سرور عبور کند."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"متأسفیم، تلاش ناموفق بود. دوباره امتحان کنید."</string>
<string name="print_error_retry" msgid="1426421728784259538">"امتحان مجدد"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"این چاپگر اکنون در دسترس نیست."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"نمایش پیشنمایش امکانپذیر نیست"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"در حال آمادهسازی پیشنمایش…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index dfd98f8..cf051f8 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Käynnistä uudelleen"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ei yhteyttä tulostimeen"</string>
<string name="reason_unknown" msgid="5507940196503246139">"tuntematon"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ei käytettävissä"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Käytetäänkö palvelua <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Asiakirja saattaa kulkea yhden tai useamman palvelimen kautta matkalla tulostimeen."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Ei valitettavasti onnistunut. Yritä uudelleen."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Yritä uudelleen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Tämä tulostin ei ole käyttävissä juuri nyt."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Esikatselua ei voi näyttää."</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Esikatselua valmistellaan…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index a95d565..11d2875 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Recommencer"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante"</string>
<string name="reason_unknown" msgid="5507940196503246139">"inconnu"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> — indisponible"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Utiliser <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Votre document peut passer par un ou plusieurs serveurs avant d\'arriver à l\'imprimante."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Échec de l\'action. Réessayez."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Cette imprimante n\'est pas accessible pour le moment."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Impossible d\'afficher l\'aperçu"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Préparation de l\'aperçu en cours…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index dd1f490..6b89281 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Redémarrer"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante."</string>
<string name="reason_unknown" msgid="5507940196503246139">"inconnue"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – indisponible"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Utiliser <xliff:g id="SERVICE">%1$s</xliff:g> ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Votre document peut passer par un ou plusieurs serveurs avant d\'être envoyé sur l\'imprimante."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Échec de l\'opération. Veuillez réessayer."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Cette imprimante n\'est pas disponible actuellement."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Impossible d\'afficher l\'aperçu"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Préparation de l\'aperçu en cours…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 81e080e..7ddc9f8 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Non hai conexión coa impresora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"descoñecido"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: non dispoñible"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Queres usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"É posible que o teu documento pase por un ou máis servidores antes de imprimirse."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Non funcionou. Téntao de novo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Tentar de novo"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora non está dispoñible nestes momentos."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Non se pode mostrar a vista previa"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparando a vista previa…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 44ede86..6a7e0df 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"પુનઃપ્રારંભ કરો"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"પ્રિન્ટર માટે કોઈ કનેક્શન નથી"</string>
<string name="reason_unknown" msgid="5507940196503246139">"અજાણ્યું"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – અનુપલબ્ધ"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> નો ઉપયોગ કરીએ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"તમારો દસ્તાવેજ પ્રિન્ટર સુધીના તેના માર્ગમાં એક અથવા વધુ સર્વર્સથી પસાર થઈ શકે છે."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"માફ કરશો, તે કામ કરતું નહોતું. ફરીથી પ્રયાસ કરો."</string>
<string name="print_error_retry" msgid="1426421728784259538">"ફરી પ્રયાસ કરો"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"આ પ્રિન્ટર અત્યારે ઉપલબ્ધ નથી."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"પૂર્વાવલોકન પ્રદર્શિત કરી શકતાં નથી"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"પૂર્વાવલોકનની તૈયારી કરી રહ્યું છે..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index f75630e..377dc62 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटर के लिए कोई कनेक्शन नहीं"</string>
<string name="reason_unknown" msgid="5507940196503246139">"अज्ञात"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – अनुपलब्ध"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> का उपयोग करें?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"प्रिंटर पर जाते समय आपका दस्तावेज़ एक या अधिक सर्वर से गुज़र सकता है."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"क्षमा करें, उससे बात नहीं बनी. पुन: प्रयास करें."</string>
<string name="print_error_retry" msgid="1426421728784259538">"फिर से प्रयास करें"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"यह प्रिंटर इस समय उपलब्ध नहीं है."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकन प्रदर्शित नहीं किया जा सकता"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकन तैयार हो रहा है..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index bd29d02..8550be4 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -81,7 +81,6 @@
<string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze s pisačem"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nepoznato"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – zadatak nije dostupan"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite li upotrijebiti uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Na putu do pisača vaš dokument može proći kroz jedan ili više poslužitelja."</string>
<string-array name="color_mode_labels">
@@ -101,5 +100,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Nažalost, to nije uspjelo. Pokušajte ponovo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovno"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Pisač trenutačno nije dostupan."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Pregled nije dostupan"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 356cb76..20789a3 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Újraindítás"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nincs kapcsolat a nyomtatóval"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ismeretlen"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nem érhető el"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Használni szeretné a következő szolgáltatást: <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"A dokumentum áthaladhat egy vagy több szerveren, mielőtt a nyomtatóhoz érne."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Sajnáljuk, de nem sikerült. Próbálja újra."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Újra"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ez a nyomtató jelenleg nem érhető el."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Nem lehet megjeleníteni az előnézetet"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Előnézet előkészítése…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 2d10166..8950338 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Վերագործարկել"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Տպիչի հետ կապ չկա"</string>
<string name="reason_unknown" msgid="5507940196503246139">"անհայտ"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> տպիչն անհասանելի է"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Օգտագործե՞լ <xliff:g id="SERVICE">%1$s</xliff:g>-ը:"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Հնարավոր է՝ փաստաթուղթը մի քանի սերվերներով անցնի մինչ տպվելը:"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Չհաջողվեց: Նորից փորձեք:"</string>
<string name="print_error_retry" msgid="1426421728784259538">"Կրկնել"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Տպիչն այս պահին հասանելի չէ:"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Նախադիտումը հնարավոր չէ"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Նախադիտումը պատրաստվում է…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 8e20d27..9b72250 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Mulai Ulang"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Tidak ada sambungan ke printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"tak diketahui"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – tidak tersedia"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Gunakan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumen Anda dapat melewati satu atau beberapa server saat menuju printer."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Maaf, tidak berhasil. Coba lagi."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Coba lagi"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Saat ini printer ini tidak tersedia."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Tidak dapat menampilkan pratinjau"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Menyiapkan pratinjau..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 73660fb..37abb5a 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Endurræsa"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Engin tenging við prentara"</string>
<string name="reason_unknown" msgid="5507940196503246139">"óþekkt"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ekki í boði"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Nota <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Skjalið gæti þurft að fara í gegnum einn eða fleiri þjóna á leið sinni til prentarans."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Þetta virkaði því miður ekki. Reyndu aftur."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Reyna aftur"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Þessi prentari er ekki í boði núna."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Ekki hægt að birta forskoðun"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Undirbýr forskoðun…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 46a570d..dd4a8cb 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Riavvia"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nessun collegamento alla stampante"</string>
<string name="reason_unknown" msgid="5507940196503246139">"sconosciuto"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - non disponibile"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Utilizzare <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Il tuo documento potrebbe passare da uno o più server per raggiungere la stampante."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Non ha funzionato. Riprova."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Riprova"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Al momento la stampante non è disponibile."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Impossibile visualizzare l\'anteprima"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparazione anteprima…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index c26c3d1..1d813bb 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"הפעל מחדש"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"אין חיבור למדפסת"</string>
<string name="reason_unknown" msgid="5507940196503246139">"לא ידוע"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – לא זמינה"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"האם להשתמש ב-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ייתכן שהמסמך שלך יעבור בשרת אחד או יותר בדרכו למדפסת."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"מצטערים, אך זה לא עבד. נסה שוב."</string>
<string name="print_error_retry" msgid="1426421728784259538">"נסה שוב"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"המדפסת הזו אינה זמינה כעת."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"לא ניתן להציג תצוגה מקדימה"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"מכין תצוגה מקדימה…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index a6e243f..946052a 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"再試行"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"プリンタに接続されていません"</string>
<string name="reason_unknown" msgid="5507940196503246139">"不明"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>–使用不可"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>を利用しますか?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ドキュメントは1つ以上のサーバーを経由してプリンタに送信されることがあります。"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"エラーです。もう一度お試しください。"</string>
<string name="print_error_retry" msgid="1426421728784259538">"再試行"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"現在このプリンターは使用できません。"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"プレビューを表示できません"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"プレビューを準備しています…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 2608ed4..94152b1 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"გადატვირთვა"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"პრინტერთან კავშირი არ არის"</string>
<string name="reason_unknown" msgid="5507940196503246139">"უცნობი"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – მიუწვდომელია"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"გსურთ, გამოიყენოთ <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"პრინტერამდე გზად დოკუმენტმა შეიძლება ერთი ან მეტი სერვერი გაიაროს."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"უკაცრავად, ვერ მოხერხდა. სცადეთ ისევ."</string>
<string name="print_error_retry" msgid="1426421728784259538">"გამეორება"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"პრინტერი ამჟამად მიუწვდომელია."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"გადახედვის ჩვენება ვერ ხერხდება"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"მზადდება გადახედვა…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index def0c3c..2bc5ab6 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Қайта бастау"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Принтермен байланыс жоқ"</string>
<string name="reason_unknown" msgid="5507940196503246139">"белгісіз"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – қол жетімсіз"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> қолданылсын ба?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Құжат принтерге жеткенше бір немесе бірнеше серверден өтуі мүмкін."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Кешіріңіз, бұл нәтиже бермеді. Әрекетті қайталаңыз."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Қайталау"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Бұл принтер дәл қазір қол жетімді емес."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Алдын ала қарауды көрсету мүмкін емес"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Алдын ала қарау дайындалуда…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 24048cf..330edf5 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើមឡើងវិញ"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មានការភ្ជាប់ទៅម៉ាស៊ីនបោះពុម្ព"</string>
<string name="reason_unknown" msgid="5507940196503246139">"មិនស្គាល់"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – មិនអាចប្រើបាន"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"ប្រើ <xliff:g id="SERVICE">%1$s</xliff:g> ឬ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ឯកសាររបស់អ្នកអាចនឹងឆ្លងកាត់ម៉ាស៊ីនមេមួយ ឬច្រើននៅពេលដែលវាធ្វើដំណើរទៅកាន់ម៉ាស៊ីនបោះពុម្ព។"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"សូមទោស វាមិនដំណើរការទេ។ ព្យាយាមម្ដងទៀត។"</string>
<string name="print_error_retry" msgid="1426421728784259538">"ព្យាយាមម្ដងទៀត"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ឥឡូវនេះ ម៉ាស៊ីនបោះពុម្ពនេះមិនអាចប្រើបាន។"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"មិនអាចបង្ហាញការមើលជាមុនបានទេ"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"កំពុងរៀបចំមើលជាមុន…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index af20965..f1cef86 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"ಮರುಪ್ರಾರಂಭಿಸು"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ಮುದ್ರಕಕ್ಕೆ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ಅಜ್ಞಾತ"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ಬಳಸುವುದೇ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ನಿಮ್ಮ ಡಾಕ್ಯುಮೆಂಟ್ ಪ್ರಿಂಟರ್ಗೆ ಹೋಗುವ ಸಂದರ್ಭದಲ್ಲಿ ಒಂದು ಅಥವಾ ಅದಕ್ಕಿಂತ ಹೆಚ್ಚು ಸರ್ವರ್ಗಳ ಮೂಲಕ ಹಾದು ಹೋಗಬಹುದು."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ಕ್ಷಮಿಸಿ, ಅದು ಕೆಲಸ ಮಾಡುತ್ತಿಲ್ಲ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="print_error_retry" msgid="1426421728784259538">"ಮರುಪ್ರಯತ್ನಿಸು"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ಈ ಪ್ರಿಂಟರ್ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"ಪೂರ್ವವೀಕ್ಷಣೆ ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"ಪೂರ್ವವೀಕ್ಷಣೆ ತಯಾರಾಗುತ್ತಿದೆ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 0b297a2..d3cc967 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"다시 시작"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"프린터와 연결되지 않음"</string>
<string name="reason_unknown" msgid="5507940196503246139">"알 수 없음"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – 사용할 수 없음"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>을(를) 사용할까요?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"문서가 프린터로 전송되는 중에 하나 이상의 서버를 통과할 수 있습니다."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"죄송합니다. 오류가 발생했습니다. 다시 시도해 보세요."</string>
<string name="print_error_retry" msgid="1426421728784259538">"다시 시도"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"현재 이 프린터를 사용할 수 없습니다."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"미리보기를 표시할 수 없음"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"미리보기 준비 중…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index 85b2526..d84e5d8 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Кайра баштоо"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер менен байланыш жок"</string>
<string name="reason_unknown" msgid="5507940196503246139">"белгисиз"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – жеткиликтүү эмес"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> колдонулсунбу?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Принтерге жеткиче документиңиз бир же андан көп серверлерден өтүшү мүмкүн."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Кечиресиз, иштеген жок. Дагы бир жолу аракет кылып көрүңүз."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Дагы бир жолу аракет кылуу"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Учурда бул принтерди колдонуу мүмкүн эмес."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Алдын ала көрүнүшү көрсөтүлбөй жатат"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Алдын-ала көрүүгө даярданууда…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 81ace83..6a69053 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"ປິດເປີດໃໝ່"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ບໍ່ມີການເຊື່ອມຕໍ່ຫາເຄື່ອງພິມ"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ບໍ່ຮູ້ຈັກ"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - ບໍ່ມີຢູ່"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"ໃຊ້ <xliff:g id="SERVICE">%1$s</xliff:g> ບໍ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ເອກະສານຂອງທ່ານອາດເດີນທາງຜ່ານໜຶ່ງ ຫຼື ຫຼາຍເຊີບເວີ ເພື່ອໄປຮອດເຄື່ອງພິມ."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ຂໍອະໄພ, ໃຊ້ບໍ່ໄດ້. ໃຫ້ລອງໃໝ່ອີກເທື່ອນຶ່ງ."</string>
<string name="print_error_retry" msgid="1426421728784259538">"ລອງໃໝ່"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ບໍ່ສາມາດໃຊ້ເຄື່ອງພິມນີ້ໃນເວລານີ້ໄດ້."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"ບໍ່ສາມາດສະແດງຕົວຢ່າງໄດ້"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"ກຳລັງກະກຽມຕົວຢ່າງ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 40bc7f1..ddcaba7 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Paleisti iš naujo"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nėra ryšio su spausdintuvu"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nežinoma"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ – nepasiekiama"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Naudoti „<xliff:g id="SERVICE">%1$s</xliff:g>“?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Kai dokumentas siunčiamas į spausdintuvą, jis gali būti perduodamas per vieną ar daugiau serverių."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Deja, tai neveikia. Bandykite dar kartą."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Bandykite dar kartą"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Šis spausdintuvas šiuo metu nepasiekiamas."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Nepavyksta pateikti peržiūros"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Ruošiama peržiūra…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 11e689b..50ba32d 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -81,7 +81,6 @@
<string name="restart" msgid="2472034227037808749">"Restartēt"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nav savienojuma ar printeri"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nezināms"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> — nav pieejams"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Vai izmantot pakalpojumu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokuments, iespējams, tiek pārsūtīts caur vienu vai vairākiem serveriem, līdz tas nonāk līdz printerim."</string>
<string-array name="color_mode_labels">
@@ -101,5 +100,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Diemžēl tas neizdevās. Mēģiniet vēlreiz."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Mēģināt vēlreiz"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Šis printeris šobrīd nav pieejams."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Nevar attēlot priekšskatījumu"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Notiek priekšskatījuma sagatavošana..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index bc2b498..a189042 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Рестартирај"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Нема поврзување со печатач"</string>
<string name="reason_unknown" msgid="5507940196503246139">"непознато"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - недостапен"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Користи <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"На пат до печатачот, документот може да помине преку еден или повеќе сервери."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"За жал, тоа не успеа. Обидете се повторно."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Обиди се повторно"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Овој печатач не е достапен во моментов."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Прегледот не може да се прикаже"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Се подготвува преглед…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index ade7fb39..5625632 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"പുനരാരംഭിക്കുക"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"പ്രിന്ററിൽ കണക്ഷനൊന്നുമില്ല"</string>
<string name="reason_unknown" msgid="5507940196503246139">"അജ്ഞാതം"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ലഭ്യമല്ല"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ഉപയോഗിക്കണോ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"നിങ്ങളുടെ പ്രമാണം പ്രിന്ററിലേക്ക് പോകുന്നതിനിടെ അത് ഒന്നോ അതിലധികമോ സെർവറുകളിലൂടെ കടന്നുപോകാനിടയുണ്ട്."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ക്ഷമിക്കണം, അത് പ്രവർത്തിച്ചില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="print_error_retry" msgid="1426421728784259538">"വീണ്ടും ശ്രമിക്കുക"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ഈ പ്രിന്ററർ ഇപ്പോൾ ലഭ്യമല്ല."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"പ്രിവ്യൂ കാണിക്കാൻ കഴിയില്ല"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"പ്രിവ്യൂ തയ്യാറാക്കുന്നു…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 133d88c..7797944 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Дахин эхлүүлэх"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер холбогдоогүй байна"</string>
<string name="reason_unknown" msgid="5507940196503246139">"тодорхойгүй"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ашиглах боломжгүй"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>-г ашиглах уу?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Таны документ хэвлэгчид иртэл нэг эсвэл хэд хэдэн серверээр дамжина."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Уучлаарай, ажилласангүй. Дахин оролдоно уу."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Дахин оролдох"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Одоо хэвлэгч ашиглах боломжгүй."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Урьдчилан үзүүлэх боломжгүй"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Урьдчилан харахыг бэлтгэж байна…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index 2b3b29f..ee09db2 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटरवर कोणतेही कनेक्शन नाही"</string>
<string name="reason_unknown" msgid="5507940196503246139">"अज्ञात"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – अनुपलब्ध"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> वापरायची?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"आपला दस्तऐवज प्रिंटरपर्यंत पोहचण्यापूर्वी एक किंवा अधिक सर्व्हरद्वारे जाऊ शकतो."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"क्षमस्व, त्याने कार्य केले नाही. पुन्हा प्रयत्न करा."</string>
<string name="print_error_retry" msgid="1426421728784259538">"पुन्हा प्रयत्न करा"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"हा प्रिंटर आत्ता उपलब्ध नाही."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकन प्रदर्शित करू शकत नाही"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकनाची तयारी करत आहे..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index 73104e1..4042c71 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Mulakan semula"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Tiada sambungan ke pencetak"</string>
<string name="reason_unknown" msgid="5507940196503246139">"tidak diketahui"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – tidak tersedia"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Gunakan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumen anda mungkin melalui satu atau beberapa pelayan dalam perjalanan ke pencetak."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Maaf, itu tidak berjaya. Cuba lagi."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Cuba semula"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Pencetak ini tidak tersedia sekarang."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Tidak dapat memaparkan pratonton"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Menyediakan pratonton..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index 8cec068..f34ca67 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"အစက ပြန်စရန်"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string>
<string name="reason_unknown" msgid="5507940196503246139">"အကြောင်းအရာ မသိရှိ"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – မတွေ့ရှိပါ"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ကိုသုံးမလား။"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"သင်၏ စာရွက်စာတမ်းများသည် ပရင်တာထံသို့ သွားစဉ် ဆာဗာ တစ်ခု သို့မဟုတ် ပိုများပြီး ဖြတ်ကျော်နိုင်ရသည်။"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ဆော်ရီး၊ အဲဒါ အလုပ်မဖြစ်ခဲ့ပါ။ ထပ် စမ်းပါ။"</string>
<string name="print_error_retry" msgid="1426421728784259538">"ထပ်စမ်း"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ဒီပရင်တာမှာ ယခုအချိန်မှာ မရနိုင်ပါ။"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"အစမ်းကြည့်ခြင်းကို ပြသ၍မရပါ"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"အစမ်းကြည့်ရန် ပြင်ဆင်နေ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 0a6f6c3..6b74765 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Start på nytt"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse med skriveren"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ukjent"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – utilgjengelig"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Vil du bruke <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumentet ditt kan gå via flere tjenere før det når skriveren."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Beklager, det fungerte ikke. Prøv på nytt."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Prøv på nytt"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Denne skriveren er ikke tilgjengelig akkurat nå."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan ikke vise forhåndsvisningen"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Forbereder forhåndsvisningen …"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 5af3a04..8e8bf15 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"पुनःस्टार्ट गर्नुहोस्"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिन्टरमा कुनै जडान छैन"</string>
<string name="reason_unknown" msgid="5507940196503246139">"अज्ञात"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - अनुपलब्ध"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> प्रयोग गर्ने हो?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"तपाईँको कागजात प्रिन्टरमा जाँदा यसको मार्गमा एक वा धेरै सर्भरहरू पार हुनसक्छन्।"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"माफ गर्नुहोस्, त्यसले काम गरेन। पुनः प्रयास गर्नुहोस्।"</string>
<string name="print_error_retry" msgid="1426421728784259538">"पुनःप्रयास गर्नुहोस्"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"यो प्रिन्टर अहिले उपलब्ध छैन।"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकनलाई प्रदर्शन गर्न सक्दैन"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकन तयारी..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 4afdb86..3c65d8a 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Opnieuw starten"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"onbekend"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – niet beschikbaar"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> gebruiken?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Je document kan via een of meer servers naar de printer worden verzonden."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Dat werkte niet. Probeer het opnieuw."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Opnieuw proberen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Deze printer is momenteel niet beschikbaar."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Kan voorbeeld niet weergeven"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Voorbeeld voorbereiden…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 1886ef5..934123b 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"ਰੀਸਟਾਰਟ ਕਰੋ"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ਪ੍ਰਿੰਟਰ ਲਈ ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ਅਗਿਆਤ"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ਅਣਉਪਲਬਧ"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"ਕੀ <xliff:g id="SERVICE">%1$s</xliff:g> ਵਰਤਣੀ ਹੈ?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ਤੁਹਾਡਾ ਦਸਤਾਵੇਜ਼ ਪ੍ਰਿੰਟਰ ਵਿੱਚ ਜਾਣ ਲਈ ਇੱਕ ਜਾਂ ਦੋ ਸਰਵਰਾਂ ਵਿੱਚੋਂ ਲੰਘਦਾ ਹੈ।"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ਮਾਫ਼ ਕਰਨਾ, ਉਸਨੇ ਲਾਭਕਾਰੀ ਨਹੀਂ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="print_error_retry" msgid="1426421728784259538">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ਇਹ ਪ੍ਰਿੰਟਰ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"ਝਲਕ ਨਹੀਂ ਵਿਖਾਈ ਜਾ ਸਕਦੀ"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"ਪ੍ਰੀਵਿਊ ਦੀ ਤਿਆਰੀ ਕਰ ਰਿਹਾ ਹੈ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 45649bb..80b6070 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Od nowa"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Brak połączenia z drukarką"</string>
<string name="reason_unknown" msgid="5507940196503246139">"brak informacji"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – niedostępne"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Użyć usługi <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Zanim dokument dotrze do drukarki, może przejść przez jeden lub kilka serwerów."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"To nie zadziałało. Spróbuj jeszcze raz."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Ponów próbę"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Drukarka nie jest teraz dostępna."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Nie można wyświetlić podglądu"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Przygotowuję podgląd…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 58eb24f..4bd1161 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – não disponível"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Seu documento pode passar por um ou mais servidores até chegar à impressora."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Falhou. Tente novamente."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impressora não está disponível no momento."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Não é possível exibir a visualização"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparando visualização…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 370bbb9..7660c5c 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Sem ligação à impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – indisponível"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Pretende utilizar o <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"O seu documento pode passar por um ou mais servidores no respetivo caminho para a impressora."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Lamentamos, mas isso não funcionou. Tente novam."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impressora não está atualmente disponível."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Não é possível apresentar a pré-visualização"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"A preparar a pré-visualização..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 58eb24f..4bd1161 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – não disponível"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Usar <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Seu documento pode passar por um ou mais servidores até chegar à impressora."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Falhou. Tente novamente."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impressora não está disponível no momento."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Não é possível exibir a visualização"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparando visualização…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 1097d56..dd38c31 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -81,7 +81,6 @@
<string name="restart" msgid="2472034227037808749">"Reporniți"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nu există conexiune la o imprimantă"</string>
<string name="reason_unknown" msgid="5507940196503246139">"necunoscut"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - indisponibil"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Folosiți <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Documentul poate trece prin unul sau mai multe servere pe calea spre imprimantă."</string>
<string-array name="color_mode_labels">
@@ -101,5 +100,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Ne pare rău, operațiunea nu a reușit. Încercați din nou."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Reîncercați"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Această imprimantă nu este disponibilă momentan."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Previzualizarea nu se poate afișa"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Se pregătește previzualizarea..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index 24b1e0d..6c074ed 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Повторить"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Нет связи с принтером"</string>
<string name="reason_unknown" msgid="5507940196503246139">"неизвестно"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недоступен"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Использовать <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Документ может пересылаться на принтер через несколько серверов."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Ошибка. Повторите попытку."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Повторить"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Принтер не готов."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Сбой предварительного просмотра"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Подготовка изображения…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 707c151..8278aee 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"යළි අරඹන්න"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"මුද්රණ යන්ත්රය වෙත සම්බන්ධය නැත"</string>
<string name="reason_unknown" msgid="5507940196503246139">"නොදනී"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ලද නොහැක"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> භාවිත කරන්නද?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"ඔබගේ ලේඛනය මුද්රණ යන්ත්රයට යන අතරතුර සේවාදායක එකක් හෝ කිහිපයක් හරහා යා හැක."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"කණගාටුයි, එය වැඩ නොකරයි. නැවත උත්සහ කරන්න."</string>
<string name="print_error_retry" msgid="1426421728784259538">"නැවත උත්සාහ කරන්න"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"දැන් මෙම මුද්රණ යන්ත්රය නොපවතී."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"පෙරදසුන සංදර්ශනය කළ නොහැකිය"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"පෙරදසුන සූදානම් කරමින්…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 1f13b54..610fe99 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Spustiť znova"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Žiadne pripojenie k tlačiarni"</string>
<string name="reason_unknown" msgid="5507940196503246139">"neznáme"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nie je k dispozícii"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Použiť službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Skôr ako sa váš dokument dostane do tlačiarne, môže prejsť jedným alebo viacerými servermi."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Je nám to ľúto, nefungovalo to. Skúste to znova."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Opakovať"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Táto tlačiareň nie je momentálne k dispozícii."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Ukážka sa nedá zobraziť"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Pripravuje sa ukážka..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 3f8a5e6..b5124b4 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Začni znova"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ni povezave s tiskalnikom"</string>
<string name="reason_unknown" msgid="5507940196503246139">"neznano"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ni na voljo"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite uporabiti storitev <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument gre lahko na poti do tiskalnika skozi enega ali več strežnikov."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"To žal ni delovalo. Poskusite znova."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Poskusi znova"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ta tiskalnik trenutno ni na voljo."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Predogleda ni mogoče prikazati"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Priprava predogleda …"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index 0b843d7..27bbbf9 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Rifillo"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Printeri nuk është i lidhur"</string>
<string name="reason_unknown" msgid="5507940196503246139">"e panjohur"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nuk mundësohet"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Përdor <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokumenti mund të kalojë përmes një ose shumë serverëve deri te printeri."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Na vjen keq, nuk funksionoi! Provo përsëri."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Provo sërish"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ky printer nuk mund të përdoret tani."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Nuk mund të shfaqet paraafishimi"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Po përgatit shikimin paraprak…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 8baa23c..ea6fcb7 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -81,7 +81,6 @@
<string name="restart" msgid="2472034227037808749">"Поново покрени"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Нема везе са штампачем"</string>
<string name="reason_unknown" msgid="5507940196503246139">"непознато"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недоступан"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Желите ли да користите <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Документ може да прође кроз један или више сервера на путу до штампача."</string>
<string-array name="color_mode_labels">
@@ -101,5 +100,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Жао нам је, ово није успело. Покушајте поново."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Покушајте поново"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Овај штампач тренутно није доступан."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Није успео приказ прегледа"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Припрема прегледа..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 64b6b20..c909e19 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Starta om"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen anslutning till skrivaren"</string>
<string name="reason_unknown" msgid="5507940196503246139">"okänt"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – inte tillgänglig"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Vill du använda <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"På vägen till skrivaren kan dokumentet passera en eller flera servrar."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Det fungerade tyvärr inte. Försök igen."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Försök igen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Den här skrivaren är inte tillgänglig just nu."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Det gick inte att visa förhandsgranskningen"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Förbereder förhandsvisning ..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index b3ffa71..bd14117 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Anzisha upya"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
<string name="reason_unknown" msgid="5507940196503246139">"haijulikani"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - haipatikani"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Ungependa kutumia <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Huenda hati yako ikapitia seva moja au zaidi kabla ya kufika kwenye printa."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Samahani, hiyo haikufanya kazi. Jaribu tena."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Jaribu tena"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Printa hii haipatikani kwa sasa."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Haiwezi kupakia onyesho la kuchungulia"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Inaandaa onyesho la kuchungulia..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index 7ae3cbc..782ebf2 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"மீண்டும் தொடங்கு"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"அச்சுப்பொறியுடன் இணைக்கப்படவில்லை"</string>
<string name="reason_unknown" msgid="5507940196503246139">"அறியப்படாதது"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – இல்லை"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ஐப் பயன்படுத்தவா?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"உங்கள் ஆவணம் பிரிண்டருக்குச் செல்லும் வழியில் ஒன்று அல்லது அதற்கு மேற்பட்ட சேவையகங்களைக் கடந்து செல்லக்கூடும்."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"செயல்படவில்லை. மீண்டும் முயலவும்."</string>
<string name="print_error_retry" msgid="1426421728784259538">"மீண்டும் முயலவும்"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"இப்போது பிரிண்டர் இல்லை."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"மாதிரிக்காட்சியைக் காட்ட முடியவில்லை"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"மாதிரிக்காட்சியைத் தயார்படுத்துகிறது…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index 9e8dea2..ca393c839 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"పునఃప్రారంభించు"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ప్రింటర్కు కనెక్షన్ లేదు"</string>
<string name="reason_unknown" msgid="5507940196503246139">"తెలియదు"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – అందుబాటులో లేదు"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ని ఉపయోగించాలా?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"మీ పత్రం ప్రింటర్కు వెళ్లే మార్గంలో ఒకటి లేదా అంతకంటే ఎక్కువ సర్వర్ల గుండా వెళ్లవచ్చు."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"క్షమించండి, అది పని చేయలేదు. మళ్లీ ప్రయత్నించండి."</string>
<string name="print_error_retry" msgid="1426421728784259538">"మళ్లీ ప్రయత్నించు"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ఈ ప్రింటర్ ప్రస్తుతం అందుబాటులో లేదు."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"పరిదృశ్యాన్ని ప్రదర్శించడం సాధ్యపడలేదు"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"పరిదృశ్యం సిద్ధమవుతోంది…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index c623dd7..92b960e 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"เริ่มต้นใหม่"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ไม่มีการเชื่อมต่อไปยังเครื่องพิมพ์"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ไม่ทราบ"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"ใช้ <xliff:g id="SERVICE">%1$s</xliff:g> ไหม"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"เอกสารของคุณอาจต้องผ่านมากกว่าหนึ่งเซิร์ฟเวอร์ระหว่างส่งไปยังเครื่องพิมพ์"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"ขออภัย ไม่สามารถใช้งานได้ ลองอีกครั้ง"</string>
<string name="print_error_retry" msgid="1426421728784259538">"ลองอีกครั้ง"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"เครื่องพิมพ์นี้ไม่พร้อมใช้งานในขณะนี้"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"ไม่สามารถแสดงตัวอย่าง"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"กำลังเตรียมการแสดงตัวอย่าง…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 0494cf6..5a73659 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"I-restart"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Hindi nakakonekta sa printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"hindi alam"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – hindi available"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Gusto mo bang gamitin ang <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Bago ma-print ang iyong dokumento, maaari itong dumaan sa isa o higit pang mga server."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Paumanhin, hindi iyon gumana. Subukang muli."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Subukang muli"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Hindi available ang printer na ito sa ngayon."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Hindi maipakita ang preview"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Inihahanda ang preview…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index 2818f36..f17bc9d 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Yeniden başlat"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Yazıcı bağlantısı yok"</string>
<string name="reason_unknown" msgid="5507940196503246139">"bilinmiyor"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – kullanılamıyor"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> kullanılsın mı?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokümanınız yazıcıya giderken bir veya daha fazla sunucudan geçebilir."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Maalesef bu işe yaramadı. Tekrar deneyin."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Yeniden dene"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Bu yazı şu anda kullanılamıyor."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Önizleme gösterilemiyor"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Önizleme hazırlanıyor…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 41051af..9629ad3 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -82,7 +82,6 @@
<string name="restart" msgid="2472034227037808749">"Перезапустити"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Немає з’єднання з принтером"</string>
<string name="reason_unknown" msgid="5507940196503246139">"невідомо"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" не доступне"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Увімкнути службу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Коли ви надсилаєте документ на принтер, він може проходити через декілька серверів."</string>
<string-array name="color_mode_labels">
@@ -102,5 +101,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"На жаль, сталася помилка. Повторіть спробу."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Повторити"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Цей принтер зараз недоступний."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Не вдалося відкрити попередній перегляд"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Підготовка до попереднього перегляду…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index a94b16f..0d01ee2 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"دوبارہ شروع کریں"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"پرنٹر کے ساتھ کوئی کنکشن نہیں ہے"</string>
<string name="reason_unknown" msgid="5507940196503246139">"نامعلوم"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – دستیاب نہیں ہے"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> استعمال کریں؟"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"آپ کی دستاویز پرنٹر تک جاتے ہوئے ممکن ہے ایک یا زیادہ سرورز سے گزرے۔"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"معذرت، اس نے کام نہیں کیا۔ دوبارہ کوشش کریں۔"</string>
<string name="print_error_retry" msgid="1426421728784259538">"دوبارہ کوشش کریں"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"یہ پرنٹر ابھی دستیاب نہیں ہے۔"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"پیش منظر ڈسپلے نہیں ہو سکتا"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"پیش منظر کو تیار کیا جا رہا ہے…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index a6af5bd..1f379d9 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Qayta boshlash"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Printer ulanmagan"</string>
<string name="reason_unknown" msgid="5507940196503246139">"noma’lum"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – mavjud emas"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> xizmatidan foydalanilsinmi?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Hujjatingiz chop etilishidan oldin bir yoki bir necha serverlardan o‘tishi mumkin."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Kechirasiz, ishlamadi. Qayta urinib ko‘ring."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Qayta urinish"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ushbu printer hozirda mavjud emas."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Oldindan ko‘rsatib bo‘lmaydi"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Dastlabki ko\'rishga tayyorlanmoqda…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index df9e1a4..b931557 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Bắt đầu lại"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Không có kết nối nào với máy in"</string>
<string name="reason_unknown" msgid="5507940196503246139">"không xác định"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – không khả dụng"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Sử dụng <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Tài liệu của bạn có thể đi qua một hoặc nhiều máy chủ trên đường đến máy in."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Rất tiếc, tính năng đó không hoạt động. Hãy thử lại."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Thử lại"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Máy in này hiện không khả dụng."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Không thể hiển thị bản xem trước"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Đang chuẩn bị xem trước…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index fb30e44..e523d48 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"重新开始"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"未与打印机建立连接"</string>
<string name="reason_unknown" msgid="5507940196503246139">"未知"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - 无法使用"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"要使用<xliff:g id="SERVICE">%1$s</xliff:g>吗?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"您的文档可能会通过一个或多个服务器发送至打印机。"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,7 @@
<string name="print_error_default_message" msgid="8602678405502922346">"抱歉,操作失败。请重试。"</string>
<string name="print_error_retry" msgid="1426421728784259538">"重试"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"该打印机目前无法使用。"</string>
+ <!-- no translation found for print_cannot_load_page (6179560924492912009) -->
+ <skip />
<string name="print_preparing_preview" msgid="3939930735671364712">"即将显示预览…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index f7c8fc9..4411a23 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"重新開始"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與打印機連線"</string>
<string name="reason_unknown" msgid="5507940196503246139">"不明"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – 無法使用"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"要使用 <xliff:g id="SERVICE">%1$s</xliff:g> 嗎?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"您的文件可能會通過一部或多部伺服器才傳送至打印機。"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"很抱歉,行不通。請再試一次。"</string>
<string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"這部打印機目前無法使用。"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"無法顯示預覽"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"正在準備預覽…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index aa18f3c..98126a7 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"重新開始"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與印表機建立連線"</string>
<string name="reason_unknown" msgid="5507940196503246139">"不明"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – 無法使用"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"要使用「<xliff:g id="SERVICE">%1$s</xliff:g>」嗎?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"您的文件可能會透過一或多個伺服器輾轉傳送至印表機。"</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"很抱歉,無法執行這項操作。請再試一次。"</string>
<string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"這台印表機目前無法使用。"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"無法顯示預覽畫面"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"正在準備預覽…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index 9cfcb33..f2b4990 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -80,7 +80,6 @@
<string name="restart" msgid="2472034227037808749">"Qala kabusha"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"Akukho ukuxhumana kuphrinta"</string>
<string name="reason_unknown" msgid="5507940196503246139">"akwaziwa"</string>
- <string name="printer_unavailable" msgid="2434170617003315690">"I-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ayitholakali"</string>
<string name="print_service_security_warning_title" msgid="2160752291246775320">"Sebenzisa i-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="print_service_security_warning_summary" msgid="1427434625361692006">"Idokhumenti yakho ingase idlule iseva eyodwa noma amaningi lapho iya kuphrinta."</string>
<string-array name="color_mode_labels">
@@ -100,5 +99,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"Uxolo, lokho akusebenzanga. Zama futhi."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Zama futhi"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Le phrinta ayitholakali khona manje."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"Ayikwazi ukubonisa ukubuka kuqala"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Ilungiselela ukubuka kuqala…"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a2a3fd3..fe3ef1a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -812,4 +812,18 @@
<!-- HTTP proxy settings. The hint text field for the hostname. -->
<string name="proxy_hostname_hint" translatable="false">proxy.example.com</string>
+ <!-- Description for the screen zoom level that makes interface elements small. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_small">Small</string>
+ <!-- Description for the device's default screen zoom level. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_default">Default</string>
+ <!-- Description for the screen zoom level that makes interface elements large. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_large">Large</string>
+ <!-- Description for the screen zoom level that makes interface elements larger. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_very_large">Larger</string>
+ <!-- Description for the screen zoom level that makes interface elements largest. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_extremely_large">Largest</string>
+ <!-- Description for a custom screen zoom level. This shows the requested display
+ density in raw pixels per inch rather than using a relative description. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
new file mode 100644
index 0000000..78d7c56
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.display;
+
+import com.android.settingslib.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.util.Arrays;
+
+/**
+ * Utility methods for working with display density.
+ */
+public class DisplayDensityUtils {
+ private static final String LOG_TAG = "DisplayDensityUtils";
+
+ /** Minimum increment between density scales. */
+ private static final float MIN_SCALE_INTERVAL = 0.09f;
+
+ /** Minimum density scale. This is available on all devices. */
+ private static final float MIN_SCALE = 0.85f;
+
+ /** Maximum density scale. The actual scale used depends on the device. */
+ private static final float MAX_SCALE = 1.50f;
+
+ /** Summary used for "default" scale. */
+ public static final int SUMMARY_DEFAULT = R.string.screen_zoom_summary_default;
+
+ /** Summary used for "custom" scale. */
+ private static final int SUMMARY_CUSTOM = R.string.screen_zoom_summary_custom;
+
+ /**
+ * Summaries for scales smaller than "default" in order of smallest to
+ * largest.
+ */
+ private static final int[] SUMMARIES_SMALLER = new int[] {
+ R.string.screen_zoom_summary_small
+ };
+
+ /**
+ * Summaries for scales larger than "default" in order of smallest to
+ * largest.
+ */
+ private static final int[] SUMMARIES_LARGER = new int[] {
+ R.string.screen_zoom_summary_large,
+ R.string.screen_zoom_summary_very_large,
+ R.string.screen_zoom_summary_extremely_large,
+ };
+
+ /**
+ * Minimum allowed screen dimension, corresponds to resource qualifiers
+ * "small" or "sw320dp". This value must be at least the minimum screen
+ * size required by the CDD so that we meet developer expectations.
+ */
+ private static final int MIN_DIMENSION_DP = 320;
+
+ private final String[] mEntries;
+ private final int[] mValues;
+
+ private final int mDefaultDensity;
+ private final int mCurrentIndex;
+
+ public DisplayDensityUtils(Context context) {
+ final int defaultDensity = DisplayDensityUtils.getDefaultDisplayDensity(
+ Display.DEFAULT_DISPLAY);
+ if (defaultDensity <= 0) {
+ mEntries = null;
+ mValues = null;
+ mDefaultDensity = 0;
+ mCurrentIndex = -1;
+ return;
+ }
+
+ final Resources res = context.getResources();
+ final DisplayMetrics metrics = res.getDisplayMetrics();
+ final int currentDensity = metrics.densityDpi;
+ int currentDensityIndex = -1;
+
+ // Compute number of "larger" and "smaller" scales for this display.
+ final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+ final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+ final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) defaultDensity);
+ final float minScale = MIN_SCALE;
+ final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
+ 0, SUMMARIES_LARGER.length);
+ final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
+ 0, SUMMARIES_SMALLER.length);
+
+ String[] entries = new String[1 + numSmaller + numLarger];
+ int[] values = new int[entries.length];
+ int curIndex = 0;
+
+ if (numSmaller > 0) {
+ final float interval = (1 - minScale) / numSmaller;
+ for (int i = numSmaller - 1; i >= 0; i--) {
+ // Round down to a multiple of 2 by truncating the low bit.
+ final int density = ((int) (defaultDensity * (1 - (i + 1) * interval))) & ~1;
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
+ values[curIndex] = density;
+ curIndex++;
+ }
+ }
+
+ if (currentDensity == defaultDensity) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = defaultDensity;
+ entries[curIndex] = res.getString(SUMMARY_DEFAULT);
+ curIndex++;
+
+ if (numLarger > 0) {
+ final float interval = (maxScale - 1) / numLarger;
+ for (int i = 0; i < numLarger; i++) {
+ // Round down to a multiple of 2 by truncating the low bit.
+ final int density = ((int) (defaultDensity * (1 + (i + 1) * interval))) & ~1;
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = density;
+ entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
+ curIndex++;
+ }
+ }
+
+ final int displayIndex;
+ if (currentDensityIndex >= 0) {
+ displayIndex = currentDensityIndex;
+ } else {
+ // We don't understand the current density. Must have been set by
+ // someone else. Make room for another entry...
+ int newLength = values.length + 1;
+ values = Arrays.copyOf(values, newLength);
+ values[curIndex] = currentDensity;
+
+ entries = Arrays.copyOf(entries, newLength);
+ entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+
+ displayIndex = curIndex;
+ }
+
+ mDefaultDensity = defaultDensity;
+ mCurrentIndex = displayIndex;
+ mEntries = entries;
+ mValues = values;
+ }
+
+ public String[] getEntries() {
+ return mEntries;
+ }
+
+ public int[] getValues() {
+ return mValues;
+ }
+
+ public int getCurrentIndex() {
+ return mCurrentIndex;
+ }
+
+ public int getDefaultDensity() {
+ return mDefaultDensity;
+ }
+
+ /**
+ * Returns the default density for the specified display.
+ *
+ * @param displayId the identifier of the display
+ * @return the default density of the specified display, or {@code -1} if
+ * the display does not exist or the density could not be obtained
+ */
+ private static int getDefaultDisplayDensity(int displayId) {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ return wm.getInitialDisplayDensity(displayId);
+ } catch (RemoteException exc) {
+ return -1;
+ }
+ }
+
+ /**
+ * Asynchronously applies display density changes to the specified display.
+ *
+ * @param displayId the identifier of the display to modify
+ */
+ public static void clearForcedDisplayDensity(final int displayId) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.clearForcedDisplayDensity(displayId);
+ } catch (RemoteException exc) {
+ Log.w(LOG_TAG, "Unable to clear forced display density setting");
+ }
+ }
+ });
+ }
+
+ /**
+ * Asynchronously applies display density changes to the specified display.
+ *
+ * @param displayId the identifier of the display to modify
+ * @param density the density to force for the specified display
+ */
+ public static void setForcedDisplayDensity(final int displayId, final int density) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.setForcedDisplayDensity(displayId, density);
+ } catch (RemoteException exc) {
+ Log.w(LOG_TAG, "Unable to save forced display density setting");
+ }
+ }
+ });
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 589eac6..9839446 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -263,6 +263,14 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".stackdivider.ForcedResizableInfoActivity"
+ android:theme="@style/ForcedResizableTheme"
+ android:excludeFromRecents="true"
+ android:stateNotNeeded="true"
+ android:exported="false">
+ </activity>
+
<!-- Callback for dismissing screenshot notification after a share target is picked -->
<receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
android:process=":screenshot"
diff --git a/packages/SystemUI/res/anim/forced_resizable_enter.xml b/packages/SystemUI/res/anim/forced_resizable_enter.xml
new file mode 100644
index 0000000..01b8fdb
--- /dev/null
+++ b/packages/SystemUI/res/anim/forced_resizable_enter.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="0.0"
+ android:toAlpha="1.0"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:duration="280" />
diff --git a/packages/SystemUI/res/anim/forced_resizable_exit.xml b/packages/SystemUI/res/anim/forced_resizable_exit.xml
new file mode 100644
index 0000000..6f316a7
--- /dev/null
+++ b/packages/SystemUI/res/anim/forced_resizable_exit.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="160"
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:zAdjustment="top"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/forced_resizable_activity.xml b/packages/SystemUI/res/layout/forced_resizable_activity.xml
new file mode 100644
index 0000000..df245bc
--- /dev/null
+++ b/packages/SystemUI/res/layout/forced_resizable_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/forced_resizable_info_text"
+ android:textColor="#ffffff"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4f3db05..b9aa26b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -151,6 +151,7 @@
<color name="docked_divider_background">#ff000000</color>
<color name="docked_divider_handle">#ffffff</color>
+ <drawable name="forced_resizable_background">#80000000</drawable>
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
<color name="remote_input_hint">#99ffffff</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6f0f30d..25ecd888 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1530,4 +1530,6 @@
<!-- Accessibility action for moving down the docked stack divider [CHAR LIMIT=NONE] -->
<string name="accessibility_action_divider_move_right">Move right</string>
+ <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity and that things might crash/not work properly [CHAR LIMIT=NONE] -->
+ <string name="forced_resizable_info_text">App may not work with multi-window</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 21ad216..2b134af 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -40,6 +40,18 @@
<item name="android:windowBackground">@android:color/black</item>
</style>
+ <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
+ <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+ <item name="android:windowBackground">@drawable/forced_resizable_background</item>
+ <item name="android:statusBarColor">@color/transparent</item>
+ <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
+ </style>
+
+ <style name="Animation.ForcedResizable" parent="@android:style/Animation">
+ <item name="android:activityOpenEnterAnimation">@anim/forced_resizable_enter</item>
+ <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
+ </style>
+
<style name="TextAppearance.StatusBar.HeadsUp"
parent="@*android:style/TextAppearance.StatusBar">
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 1261a9a..fe7ac71 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -34,6 +34,7 @@
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -43,6 +44,7 @@
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
@@ -71,6 +73,7 @@
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.AnimationProps;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -281,6 +284,11 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mSystemBroadcastReceiver, filter);
+
+ getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
+
+ // Reload the stack view
+ reloadStackView();
}
@Override
@@ -293,15 +301,17 @@
}
@Override
- public void onEnterAnimationComplete() {
- super.onEnterAnimationComplete();
- EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ // Reload the stack view
+ reloadStackView();
}
- @Override
- protected void onResume() {
- super.onResume();
-
+ /**
+ * Reloads the stack views upon launching Recents.
+ */
+ private void reloadStackView() {
// If the Recents component has preloaded a load plan, then use that to prevent
// reconstructing the task stack
RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -324,38 +334,21 @@
loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
loader.loadTasks(this, loadPlan, loadOpts);
TaskStack stack = loadPlan.getTaskStack();
- mRecentsView.onResume(mIsVisible, false /* multiWindowChange */, stack);
+ mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0);
+ mRecentsView.updateStack(stack);
- // Animate the SystemUI scrims into view
- Task launchTarget = stack.getLaunchTarget();
- int taskCount = stack.getTaskCount();
- int launchTaskIndexInStack = launchTarget != null
- ? stack.indexOfStackTask(launchTarget)
- : 0;
- boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
+ // Update the nav bar scrim, but defer the animation until the enter-window event
boolean animateNavBarScrim = !launchState.launchedWhileDocking;
- mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
+ updateNavBarScrim(animateNavBarScrim, null);
- // If this is a new instance from a configuration change, then we have to manually trigger
- // the enter animation state, or if recents was relaunched by AM, without going through
- // the normal mechanisms
+ // If this is a new instance relaunched by AM, without going through the normal mechanisms,
+ // then we have to manually trigger the enter animation state
boolean wasLaunchedByAm = !launchState.launchedFromHome &&
!launchState.launchedFromApp;
- if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ if (wasLaunchedByAm) {
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
- mRecentsView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
-
- @Override
- public boolean onPreDraw() {
- mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
- EventBus.getDefault().post(new RecentsDrawnEvent());
- return true;
- }
- });
-
// Keep track of whether we launched from the nav bar button or via alt-tab
if (launchState.launchedWithAltTab) {
MetricsLogger.count(this, "overview_trigger_alttab", 1);
@@ -365,6 +358,10 @@
// Keep track of whether we launched from an app or from home
if (launchState.launchedFromApp) {
+ Task launchTarget = stack.getLaunchTarget();
+ int launchTaskIndexInStack = launchTarget != null
+ ? stack.indexOfStackTask(launchTarget)
+ : 0;
MetricsLogger.count(this, "overview_source_app", 1);
// If from an app, track the stack index of the app in the stack (for affiliated tasks)
MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
@@ -373,6 +370,7 @@
}
// Keep track of the total stack task count
+ int taskCount = mRecentsView.getStack().getTaskCount();
MetricsLogger.histogram(this, "overview_task_count", taskCount);
// After we have resumed, set the visible state until the next onStop() call
@@ -380,6 +378,29 @@
}
@Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Notify of the next draw
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+
+ @Override
+ public boolean onPreDraw() {
+ mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+ EventBus.getDefault().post(new RecentsDrawnEvent());
+ return true;
+ }
+ });
+ }
+
+ @Override
protected void onPause() {
super.onPause();
@@ -391,7 +412,34 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- EventBus.getDefault().send(new ConfigurationChangedEvent());
+ // Update the nav bar for the current orientation
+ updateNavBarScrim(false /* animateNavBarScrim */, AnimationProps.IMMEDIATE);
+
+ EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */));
+ }
+
+ @Override
+ public void onMultiWindowChanged(boolean inMultiWindow) {
+ super.onMultiWindowChanged(inMultiWindow);
+ EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */));
+
+ if (mRecentsView != null) {
+ // Reload the task stack completely
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+ loader.loadTasks(this, loadPlan, loadOpts);
+
+ mRecentsView.updateStack(loadPlan.getTaskStack());
+ }
+
+ EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
}
@Override
@@ -450,28 +498,6 @@
}
@Override
- public void onMultiWindowChanged(boolean inMultiWindow) {
- super.onMultiWindowChanged(inMultiWindow);
- EventBus.getDefault().send(new ConfigurationChangedEvent());
-
- // Reload the task stack completely
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
-
- RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
- loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, loadPlan, loadOpts);
-
- mRecentsView.onResume(mIsVisible, true /* multiWindowChange */, loadPlan.getTaskStack());
-
- EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
- }
-
- @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_TAB: {
@@ -602,6 +628,11 @@
mRecentsView.invalidate();
}
+ public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+ mRecentsView.invalidate();
+ }
+
public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
int launchToTaskId = launchState.launchedToTaskId;
@@ -688,4 +719,18 @@
});
return true;
}
+
+ /**
+ * Updates the nav bar scrim.
+ */
+ private void updateNavBarScrim(boolean animateNavBarScrim, AnimationProps animation) {
+ // Animate the SystemUI scrims into view
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ int taskCount = mRecentsView.getStack().getTaskCount();
+ boolean hasNavBarScrim = (taskCount > 0) && !ssp.hasTransposedNavBar();
+ mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
+ if (animateNavBarScrim && animation != null) {
+ mScrimViews.animateNavBarScrimVisibility(true, animation);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index ab3b79e..77f7739 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -31,8 +31,6 @@
public boolean launchedFromApp;
public boolean launchedFromAppDocked;
public boolean launchedFromHome;
- public boolean launchedReuseTaskStackViews;
- public boolean launchedHasConfigurationChanged;
public boolean launchedViaDragGesture;
public boolean launchedWhileDocking;
public int launchedToTaskId;
@@ -45,7 +43,6 @@
launchedFromAppDocked = false;
launchedToTaskId = -1;
launchedWithAltTab = false;
- launchedHasConfigurationChanged = false;
launchedViaDragGesture = false;
launchedWhileDocking = false;
}
@@ -53,10 +50,6 @@
/** Called when the configuration has changed, and we want to reset any configuration specific
* members. */
public void updateOnConfigurationChange() {
- // Reset this flag on configuration change to ensure that we recreate new task views
- launchedReuseTaskStackViews = false;
- // Set this flag to indicate that the configuration has changed since Recents last launched
- launchedHasConfigurationChanged = true;
launchedViaDragGesture = false;
launchedWhileDocking = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 2afb09a..40613f0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -47,11 +47,6 @@
// Launch states
public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState();
- // TODO: Values determined by the current context, needs to be refactored into something that is
- // agnostic of the activity context, but still calculable from the Recents component for
- // the transition into recents
- public boolean hasTransposedNavBar;
-
// Since the positions in Recents has to be calculated globally (before the RecentsActivity
// starts), we need to calculate some resource values ourselves, instead of relying on framework
// resources.
@@ -79,13 +74,6 @@
}
/**
- * Updates the configuration based on the current state of the system
- */
- void update(Rect systemInsets) {
- hasTransposedNavBar = systemInsets.right > 0;
- }
-
- /**
* Returns the activity launch state.
* TODO: This will be refactored out of RecentsConfiguration.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3ff33a8..7daef64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -43,8 +43,10 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.EventBus.Event;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
+import com.android.systemui.recents.events.activity.ForcedResizableEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
@@ -124,6 +126,13 @@
loader.loadTasks(mContext, plan, launchOpts);
}
}
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId) {
+ EventBus.getDefault().sendOntoMainThread(
+ new ForcedResizableEvent(packageName, taskId));
+
+ }
}
protected static RecentsTaskLoadPlan sInstanceLoadPlan;
@@ -131,7 +140,6 @@
protected Context mContext;
protected Handler mHandler;
TaskStackListenerImpl mTaskStackListener;
- protected boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
boolean mLaunchedWhileDocking;
@@ -200,8 +208,6 @@
public void onConfigurationChanged() {
reloadHeaderBarLayout();
updateHeaderBarLayout(null /* stack */);
- // Don't reuse task stack views if the configuration changes
- mCanReuseTaskStackViews = false;
Recents.getConfiguration().updateOnConfigurationChange();
}
@@ -583,9 +589,6 @@
calculateWindowStableInsets(systemInsets, windowRect);
windowRect.offsetTo(0, 0);
- // Update the configuration for the current state
- Recents.getConfiguration().update(systemInsets);
-
TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
mTaskStackBounds);
@@ -596,8 +599,7 @@
if (stack != null) {
stackLayout.initialize(windowRect, taskStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
- mDummyStackView.setTasks(stack, false /* notifyStackChanges */,
- false /* relayoutTaskStack */, false /* multiWindowChange */);
+ mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
}
Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
if (!taskViewBounds.equals(mLastTaskViewBounds)) {
@@ -706,7 +708,7 @@
TaskStackViewScroller stackScroller = stackView.getScroller();
stackView.updateLayoutAlgorithm(true /* boundScroll */);
- stackView.updateToInitialState();
+ stackView.updateToInitialState(true /* scrollToInitialState */);
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
@@ -773,7 +775,7 @@
// Get the transform for the running task
stackView.updateLayoutAlgorithm(true /* boundScroll */);
- stackView.updateToInitialState();
+ stackView.updateToInitialState(true /* scrollToInitialState */);
mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
stackView.getScroller().getStackScroll(), mTmpTransform, null);
return mTmpTransform;
@@ -853,10 +855,8 @@
launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
launchState.launchedFromAppDocked = mLaunchedWhileDocking;
launchState.launchedWithAltTab = mTriggeredFromAltTab;
- launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails;
- launchState.launchedHasConfigurationChanged = false;
launchState.launchedViaDragGesture = mDraggingInRecents;
launchState.launchedWhileDocking = mLaunchedWhileDocking;
@@ -906,7 +906,6 @@
} else {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
- mCanReuseTaskStackViews = true;
EventBus.getDefault().send(new RecentsActivityStartingEvent());
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
new file mode 100644
index 0000000..4738eed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppTransitionFinishedEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when an app transition has finished playing.
+ */
+public class AppTransitionFinishedEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index 0ad4681..c234c34 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -22,5 +22,10 @@
* This is sent when the Recents activity configuration has changed.
*/
public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
- // Simple event
+
+ public final boolean fromMultiWindow;
+
+ public ConfigurationChangedEvent(boolean fromMultiWindow) {
+ this.fromMultiWindow = fromMultiWindow;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
new file mode 100644
index 0000000..32d9a70
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedFirstAnimationFrameEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus.Event;
+
+/**
+ * Sent when the window animation has started when docking a task
+ */
+public class DockedFirstAnimationFrameEvent extends Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ForcedResizableEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ForcedResizableEvent.java
new file mode 100644
index 0000000..cdcabf0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ForcedResizableEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when recents received the information that an activity got forced resizable, and we need
+ * to inform the user about that.
+ */
+public class ForcedResizableEvent extends EventBus.Event {
+
+ public final String packageName;
+ public final int taskId;
+
+ public ForcedResizableEvent(String packageName, int taskId) {
+ this.packageName = packageName;
+ this.taskId = taskId;
+ }
+}
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 ea4888d..3b759c0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -52,6 +52,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -64,9 +65,8 @@
import android.util.Log;
import android.util.MutableBoolean;
import android.view.Display;
+import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
-import android.view.Surface;
-import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.view.WindowManagerGlobal;
@@ -141,6 +141,7 @@
public void onActivityPinned() { }
public void onPinnedActivityRestartAttempt() { }
public void onPinnedStackAnimationEnded() { }
+ public void onActivityForcedResizable(String packageName, int taskId) { }
}
/**
@@ -172,10 +173,17 @@
mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
}
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId)
+ throws RemoteException {
+ mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, 0, packageName)
+ .sendToTarget();
+ }
};
/**
- * List of {@link TaskStackListener} registered from {@link registerTaskStackListener}.
+ * List of {@link TaskStackListener} registered from {@link #registerTaskStackListener}.
*/
private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
@@ -393,13 +401,12 @@
}
/** Docks a task to the side of the screen and starts it. */
- public void startTaskInDockedMode(Context context, View view, int taskId, int createMode) {
+ public void startTaskInDockedMode(int taskId, int createMode) {
if (mIam == null) return;
try {
// TODO: Determine what animation we want for the incoming task
- final ActivityOptions options = ActivityOptions.makeThumbnailAspectScaleUpAnimation(
- view, null, 0, 0, view.getWidth(), view.getHeight(), null, null);
+ final ActivityOptions options = ActivityOptions.makeBasic();
options.setDockCreateMode(createMode);
options.setLaunchStackId(DOCKED_STACK_ID);
mIam.startActivityFromRecents(taskId, options.toBundle());
@@ -1045,11 +1052,34 @@
}
}
+ public void overridePendingAppTransitionMultiThumbFuture(
+ IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener,
+ boolean scaleUp) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .overridePendingAppTransitionMultiThumbFuture(future, animStartedListener,
+ scaleUp);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to override transition: " + e);
+ }
+ }
+
+ /**
+ * Returns whether the device has a transposed nav bar (on the right of the screen) in the
+ * current display orientation.
+ */
+ public boolean hasTransposedNavBar() {
+ Rect insets = new Rect();
+ getStableInsets(insets);
+ return insets.right > 0;
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_ACTIVITY_PINNED = 2;
private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
+ private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
@Override
public void handleMessage(Message msg) {
@@ -1078,6 +1108,13 @@
}
break;
}
+ case ON_ACTIVITY_FORCED_RESIZABLE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityForcedResizable(
+ (String) msg.obj, msg.arg1);
+ }
+ break;
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index dbb692c..82c81ae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -274,7 +274,9 @@
new TaskKeyLruCache.EvictionCallback() {
@Override
public void onEntryEvicted(Task.TaskKey key) {
- mActivityInfoCache.remove(key.getComponent());
+ if (key != null) {
+ mActivityInfoCache.remove(key.getComponent());
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index a930791..5a2507d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -220,6 +220,11 @@
*/
void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture);
+
+ /**
+ * Notifies when tasks in the stack have been updated.
+ */
+ void onStackTasksUpdated(TaskStack stack);
}
/**
@@ -560,14 +565,19 @@
mStackTaskList.set(allTasks);
mRawTaskList = allTasks;
+ // Update the affiliated groupings
+ createAffiliatedGroupings(context);
+
// Only callback for the newly added tasks after this stack has been updated
int addedTaskCount = addedTasks.size();
for (int i = 0; i < addedTaskCount; i++) {
mCb.onStackTaskAdded(this, addedTasks.get(i));
}
- // Update the affiliated groupings
- createAffiliatedGroupings(context);
+ // Notify that the task stack has been updated
+ if (notifyStackChanges) {
+ mCb.onStackTasksUpdated(this);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 2c34523..134b90c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -105,7 +105,11 @@
}
@Override
- public void onMoveToFullscreen() { }
+ public void onMoveToFullscreen() {
+ // Recents should be dismissed when PIP moves to fullscreen. If not, Recents will
+ // be unnecessarily shown in the scenario: PIP->Fullscreen->PIP.
+ dismissRecentsToLaunchTargetTaskOrHome();
+ }
@Override
public void onPipResizeAboutToStart() { }
@@ -309,7 +313,7 @@
RecentsActivityLaunchState launchState = config.getLaunchState();
boolean wasLaunchedByAm = !launchState.launchedFromHome &&
!launchState.launchedFromApp;
- if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+ if (wasLaunchedByAm) {
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
index aa27325..c1b47dc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -24,10 +24,13 @@
import android.graphics.Rect;
import android.os.SystemClock;
import android.os.UserHandle;
-import com.android.systemui.recents.*;
+
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.tv.views.TaskCardView;
@@ -101,8 +104,6 @@
launchState.launchedFromApp = fromThumbnail;
launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
launchState.launchedWithAltTab = mTriggeredFromAltTab;
- launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
- launchState.launchedHasConfigurationChanged = false;
Intent intent = new Intent();
intent.setClassName(RECENTS_PACKAGE, RECENTS_TV_ACTIVITY);
@@ -115,7 +116,6 @@
} else {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
- mCanReuseTaskStackViews = true;
EventBus.getDefault().send(new RecentsActivityStartingEvent());
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 22ade9f..3d0e75a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -156,4 +156,9 @@
}
}
}
+
+ @Override
+ public void onStackTasksUpdated(TaskStack stack) {
+ // Do nothing
+ }
}
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 29da476..98616f4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
+import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -32,10 +33,8 @@
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
-import android.util.Log;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.recents.Recents;
@@ -52,6 +51,7 @@
import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -82,9 +82,9 @@
}
};
- public RecentsTransitionHelper(Context context, Handler handler) {
+ public RecentsTransitionHelper(Context context) {
mContext = context;
- mHandler = handler;
+ mHandler = new Handler();
}
/**
@@ -92,7 +92,7 @@
*/
public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
final TaskStackView stackView, final TaskView taskView,
- final boolean screenPinningRequested, final Rect bounds, int destinationStack) {
+ final boolean screenPinningRequested, final Rect bounds, final int destinationStack) {
final ActivityOptions opts = ActivityOptions.makeBasic();
if (bounds != null) {
opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
@@ -101,7 +101,12 @@
final ActivityOptions.OnAnimationStartedListener animStartedListener;
final IAppTransitionAnimationSpecsFuture transitionFuture;
if (taskView != null) {
- transitionFuture = getAppTransitionFuture(task, stackView, destinationStack);
+ transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() {
+ @Override
+ public List<AppTransitionAnimationSpec> composeSpecs() {
+ return composeAnimationSpecs(task, stackView, destinationStack);
+ }
+ });
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
@@ -154,6 +159,23 @@
}
}
+ public IRemoteCallback wrapStartedListener(final OnAnimationStartedListener listener) {
+ if (listener == null) {
+ return null;
+ }
+ return new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onAnimationStarted();
+ }
+ });
+ }
+ };
+ }
+
/**
* Starts the activity for the launch task.
*
@@ -181,40 +203,21 @@
}
if (transitionFuture != null) {
- IRemoteCallback.Stub callback = null;
- if (animStartedListener != null) {
- callback = new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (animStartedListener != null) {
- animStartedListener.onAnimationStarted();
- }
- }
- });
- }
- };
- }
- try {
- synchronized (this) {
- mAppTransitionAnimationSpecs = SPECS_WAITING;
- }
- WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionMultiThumbFuture(transitionFuture,
- callback, true /* scaleUp */);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to override transition: " + e);
- }
+ ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture,
+ wrapStartedListener(animStartedListener), true /* scaleUp */);
}
}
/**
* Creates a future which will later be queried for animation specs for this current transition.
+ *
+ * @param composer The implementation that composes the specs on the UI thread.
*/
- private IAppTransitionAnimationSpecsFuture getAppTransitionFuture(final Task task,
- final TaskStackView stackView, final int destinationStack) {
+ public IAppTransitionAnimationSpecsFuture getAppTransitionFuture(
+ final AnimationSpecComposer composer) {
+ synchronized (this) {
+ mAppTransitionAnimationSpecs = SPECS_WAITING;
+ }
return new IAppTransitionAnimationSpecsFuture.Stub() {
@Override
public AppTransitionAnimationSpec[] get() throws RemoteException {
@@ -222,8 +225,7 @@
@Override
public void run() {
synchronized (RecentsTransitionHelper.this) {
- mAppTransitionAnimationSpecs = composeAnimationSpecs(task, stackView,
- destinationStack);
+ mAppTransitionAnimationSpecs = composer.composeSpecs();
RecentsTransitionHelper.this.notifyAll();
}
}
@@ -248,6 +250,17 @@
}
/**
+ * Composes the transition spec when docking a task, which includes a full task bitmap.
+ */
+ public List<AppTransitionAnimationSpec> composeDockAnimationSpec(
+ TaskView taskView, Rect transform) {
+ TaskViewTransform viewTransform = new TaskViewTransform();
+ viewTransform.fillIn(taskView);
+ return Collections.singletonList(new AppTransitionAnimationSpec(taskView.getTask().key.id,
+ RecentsTransitionHelper.composeTaskBitmap(taskView, viewTransform), transform));
+ }
+
+ /**
* Composes the animation specs for all the tasks in the target stack.
*/
private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
@@ -319,6 +332,43 @@
return new AppTransitionAnimationSpec(task.key.id, null, taskRect);
}
+ public static Bitmap composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
+ float scale = transform.scale;
+ int fromWidth = (int) (transform.rect.width() * scale);
+ int fromHeight = (int) (transform.rect.height() * scale);
+ Bitmap b = Bitmap.createBitmap(fromWidth, fromHeight,
+ Bitmap.Config.ARGB_8888);
+
+ if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
+ b.eraseColor(0xFFff0000);
+ } else {
+ Canvas c = new Canvas(b);
+ c.scale(scale, scale);
+ taskView.draw(c);
+ c.setBitmap(null);
+ }
+ return b.createAshmemBitmap();
+ }
+
+ private static Bitmap composeHeaderBitmap(TaskView taskView,
+ TaskViewTransform transform) {
+ float scale = transform.scale;
+ int fromHeaderWidth = (int) (transform.rect.width());
+ int fromHeaderHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
+ Bitmap b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
+ Bitmap.Config.ARGB_8888);
+
+ if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
+ b.eraseColor(0xFFff0000);
+ } else {
+ Canvas c = new Canvas(b);
+ c.scale(scale, scale);
+ taskView.mHeaderView.draw(c);
+ c.setBitmap(null);
+ }
+ return b.createAshmemBitmap();
+ }
+
/**
* Composes a single animation spec for the given {@link TaskView}
*/
@@ -326,21 +376,7 @@
TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
Bitmap b = null;
if (addHeaderBitmap) {
- float scale = transform.scale;
- int fromHeaderWidth = (int) (transform.rect.width());
- int fromHeaderHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
- b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
- Bitmap.Config.ARGB_8888);
-
- if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- b.eraseColor(0xFFff0000);
- } else {
- Canvas c = new Canvas(b);
- c.scale(scale, scale);
- taskView.mHeaderView.draw(c);
- c.setBitmap(null);
- }
- b = b.createAshmemBitmap();
+ b = composeHeaderBitmap(taskView, transform);
}
Rect taskRect = new Rect();
@@ -351,4 +387,8 @@
}
return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
}
+
+ public interface AnimationSpecComposer {
+ List<AppTransitionAnimationSpec> composeSpecs();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 70c4c81..a1ba493 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -19,8 +19,8 @@
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -28,9 +28,10 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -52,6 +53,7 @@
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
@@ -68,6 +70,7 @@
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -84,8 +87,6 @@
private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
- private final Handler mHandler;
-
private TaskStack mStack;
private TaskStackView mTaskStackView;
private TextView mStackActionButton;
@@ -123,18 +124,17 @@
setWillNotDraw(false);
SystemServicesProxy ssp = Recents.getSystemServices();
- mHandler = new Handler();
- mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
+ mTransitionHelper = new RecentsTransitionHelper(getContext());
mDividerSize = ssp.getDockedDividerSize(context);
mTouchHandler = new RecentsViewTouchHandler(this);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
- final float cornerRadius = context.getResources().getDimensionPixelSize(
- R.dimen.recents_task_view_rounded_corners_radius);
LayoutInflater inflater = LayoutInflater.from(context);
if (RecentsDebugFlags.Static.EnableStackActionButton) {
- mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button, this,
- false);
+ float cornerRadius = context.getResources().getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
+ mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button,
+ this, false);
mStackActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -156,19 +156,17 @@
setBackground(mBackgroundScrim);
}
- /** Set/get the bsp root node */
- public void onResume(boolean isResumingFromVisible, boolean multiWindowChange,
- TaskStack stack) {
+ /**
+ * Called from RecentsActivity when it is relaunched.
+ */
+ public void onReload(boolean isResumingFromVisible, boolean isTaskStackEmpty) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
- if (!multiWindowChange &&
- (mTaskStackView == null || !launchState.launchedReuseTaskStackViews)) {
+ if (mTaskStackView == null) {
isResumingFromVisible = false;
- removeView(mTaskStackView);
mTaskStackView = new TaskStackView(getContext());
mTaskStackView.setSystemInsets(mSystemInsets);
- mStack = mTaskStackView.getStack();
addView(mTaskStackView);
}
@@ -177,9 +175,7 @@
mLastTaskLaunchedWasFreeform = false;
// Update the stack
- mTaskStackView.onResume(isResumingFromVisible);
- mTaskStackView.setTasks(stack, isResumingFromVisible /* notifyStackChanges */,
- true /* relayoutTaskStack */, multiWindowChange);
+ mTaskStackView.onReload(isResumingFromVisible);
if (isResumingFromVisible) {
// If we are already visible, then restore the background scrim
@@ -189,12 +185,20 @@
// Otherwise, defer until the enter animation completes to animate the scrim alpha with
// the tasks for the home animation.
if (launchState.launchedWhileDocking || launchState.launchedFromApp
- || mStack.getTaskCount() == 0) {
+ || isTaskStackEmpty) {
mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
} else {
mBackgroundScrim.setAlpha(0);
}
}
+ }
+
+ /**
+ * Called from RecentsActivity when the task stack is updated.
+ */
+ public void updateStack(TaskStack stack) {
+ mStack = stack;
+ mTaskStackView.setTasks(stack, true /* allowNotifyStackChanges */);
// Update the top level view's visibilities
if (stack.getTaskCount() > 0) {
@@ -205,6 +209,13 @@
}
/**
+ * Returns the current TaskStack.
+ */
+ public TaskStack getStack() {
+ return mStack;
+ }
+
+ /**
* Returns whether the last task launched was in the freeform stack or not.
*/
public boolean isLastTaskLaunchedFreeform() {
@@ -484,31 +495,30 @@
event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
taskViewRect.right, taskViewRect.bottom);
- // Remove the task view after it is docked
- mTaskStackView.updateLayoutAlgorithm(false /* boundScroll */);
- stackLayout.getStackTransform(event.task, stackScroller.getStackScroll(), tmpTransform,
- null);
- tmpTransform.alpha = 0;
- tmpTransform.scale = 1f;
- tmpTransform.rect.set(taskViewRect);
- mTaskStackView.updateTaskViewToTransform(event.taskView, tmpTransform,
- new AnimationProps(125, Interpolators.ALPHA_OUT,
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Dock the task and launch it
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startTaskInDockedMode(getContext(), event.taskView,
- event.task.key.id, dockState.createMode);
+ final OnAnimationStartedListener startedListener = new OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
+ mTaskStackView.getStack().removeTask(event.task, AnimationProps.IMMEDIATE,
+ true /* fromDockGesture */);
+ }
+ };
- // Animate the stack accordingly
- AnimationProps stackAnim = new AnimationProps(
- TaskStackView.DEFAULT_SYNC_STACK_DURATION,
- Interpolators.FAST_OUT_SLOW_IN);
- mTaskStackView.getStack().removeTask(event.task, stackAnim,
- true /* fromDockGesture */);
- }
- }));
+ // Dock the task and launch it
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
+ final Rect taskRect = getTaskRect(event.taskView);
+ IAppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture(
+ new AnimationSpecComposer() {
+ @Override
+ public List<AppTransitionAnimationSpec> composeSpecs() {
+ return mTransitionHelper.composeDockAnimationSpec(
+ event.taskView, taskRect);
+ }
+ });
+ ssp.overridePendingAppTransitionMultiThumbFuture(future,
+ mTransitionHelper.wrapStartedListener(startedListener),
+ true /* scaleUp */);
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP);
} else {
@@ -518,6 +528,15 @@
}
}
+ private Rect getTaskRect(TaskView taskView) {
+ int[] location = taskView.getLocationOnScreen();
+ int viewX = location[0];
+ int viewY = location[1];
+ return new Rect(viewX, viewY,
+ (int) (viewX + taskView.getWidth() * taskView.getScaleX()),
+ (int) (viewY + taskView.getHeight() * taskView.getScaleY()));
+ }
+
public final void onBusEvent(DraggingInRecentsEvent event) {
if (mTaskStackView.getTaskViews().size() > 0) {
setTranslationY(event.distanceFromTop - mTaskStackView.getTaskViews().get(0).getY());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 6bdaaf9..9c8189a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -46,7 +46,7 @@
/**
* Prepares the scrim views for animating when entering Recents. This will be called before
- * the first draw.
+ * the first draw, unless we are updating the scrim on configuration change.
*/
public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
mHasNavBarScrim = hasNavBarScrim;
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 4155dd2..1c7d609 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -152,8 +152,6 @@
if (hideTask) {
tv.setVisibility(View.INVISIBLE);
- } else if (launchState.launchedHasConfigurationChanged) {
- // Just load the views as-is
} else if (launchState.launchedFromApp && !launchState.launchedWhileDocking) {
if (task.isLaunchTarget) {
tv.onPrepareLaunchTargetForEnterAnimation();
@@ -354,6 +352,12 @@
if (tv == launchingTaskView) {
tv.setClipViewInStack(false);
+ postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ tv.setClipViewInStack(true);
+ }
+ });
tv.onStartLaunchTargetLaunchAnimation(taskViewExitToAppDuration,
screenPinningRequested, postAnimationTrigger);
} else if (currentTaskOccludesLaunchTarget) {
@@ -386,7 +390,8 @@
int taskViewRemoveAnimTranslationXPx = res.getDimensionPixelSize(
R.dimen.recents_task_view_remove_anim_translation_x);
- // Disabling clipping with the stack while the view is animating away
+ // Disabling clipping with the stack while the view is animating away, this will get
+ // restored when the task is next picked up from the view pool
deleteTaskView.setClipViewInStack(false);
// Compose the new animation and transform and star the animation
@@ -395,9 +400,6 @@
@Override
public void onAnimationEnd(Animator animation) {
postAnimationTrigger.decrement();
-
- // Re-enable clipping with the stack (we will reuse this view)
- deleteTaskView.setClipViewInStack(true);
}
});
postAnimationTrigger.increment();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 83f8b7e..8a1727a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -852,7 +852,7 @@
// in screen space
float tmpP = (mMinScrollP - stackScroll) / mNumStackTasks;
int centerYOffset = (mStackRect.top - mTaskRect.top) +
- (mStackRect.height() - mTaskRect.height()) / 2;
+ (mStackRect.height() - mSystemInsets.bottom - mTaskRect.height()) / 2;
y = centerYOffset + getYForDeltaP(tmpP, 0);
z = mMaxTranslationZ;
dimAlpha = 0f;
@@ -953,14 +953,8 @@
*/
public void getTaskStackBounds(Rect windowRect, int topInset, int rightInset,
Rect taskStackBounds) {
- RecentsConfiguration config = Recents.getConfiguration();
- if (config.hasTransposedNavBar) {
- taskStackBounds.set(windowRect.left, windowRect.top + topInset,
- windowRect.right - rightInset, windowRect.bottom);
- } else {
- taskStackBounds.set(windowRect.left, windowRect.top + topInset,
- windowRect.right - rightInset, windowRect.bottom);
- }
+ taskStackBounds.set(windowRect.left, windowRect.top + topInset,
+ windowRect.right - rightInset, windowRect.bottom);
// Ensure that the new width is at most the smaller display edge size
SystemServicesProxy ssp = Recents.getSystemServices();
@@ -1105,9 +1099,11 @@
private int getScaleForExtent(Rect instance, Rect other, int value, int minValue,
@Extent int extent) {
if (extent == WIDTH) {
- return Math.max(minValue, (int) (((float) instance.width() / other.width()) * value));
+ float scale = Utilities.clamp01((float) instance.width() / other.width());
+ return Math.max(minValue, (int) (scale * value));
} else if (extent == HEIGHT) {
- return Math.max(minValue, (int) (((float) instance.height() / other.height()) * value));
+ float scale = Utilities.clamp01((float) instance.height() / other.height());
+ return Math.max(minValue, (int) (scale * value));
}
return value;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index c9cc1e9..9032871 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -22,6 +22,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -87,6 +88,8 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -109,17 +112,30 @@
public static final int DEFAULT_SYNC_STACK_DURATION = 200;
private static final int DRAG_SCALE_DURATION = 175;
- private static final float DRAG_SCALE_FACTOR = 1.05f;
+ static final float DRAG_SCALE_FACTOR = 1.05f;
private static final int LAUNCH_NEXT_SCROLL_BASE_DURATION = 216;
private static final int LAUNCH_NEXT_SCROLL_INCR_DURATION = 32;
private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
+ // The actions to perform when resetting to initial state,
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({INITIAL_STATE_UPDATE_NONE, INITIAL_STATE_UPDATE_ALL, INITIAL_STATE_UPDATE_LAYOUT_ONLY})
+ public @interface InitialStateAction {}
+ /** Do not update the stack and layout to the initial state. */
+ private static final int INITIAL_STATE_UPDATE_NONE = 0;
+ /** Update both the stack and layout to the initial state. */
+ private static final int INITIAL_STATE_UPDATE_ALL = 1;
+ /** Update only the layout to the initial state. */
+ private static final int INITIAL_STATE_UPDATE_LAYOUT_ONLY = 2;
+
LayoutInflater mInflater;
TaskStack mStack = new TaskStack();
@ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
TaskStackLayoutAlgorithm mLayoutAlgorithm;
+ // The stable layout algorithm is only used to calculate the task rect with the stable bounds
+ TaskStackLayoutAlgorithm mStableLayoutAlgorithm;
@ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
TaskStackViewScroller mStackScroller;
@ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
@@ -148,6 +164,9 @@
@ViewDebug.ExportedProperty(category="recents")
boolean mAwaitingFirstLayout = true;
@ViewDebug.ExportedProperty(category="recents")
+ @InitialStateAction
+ int mInitialState = INITIAL_STATE_UPDATE_ALL;
+ @ViewDebug.ExportedProperty(category="recents")
boolean mInMeasureLayout = false;
@ViewDebug.ExportedProperty(category="recents")
boolean mEnterAnimationComplete = false;
@@ -223,6 +242,7 @@
mViewPool = new ViewPool<>(context, this);
mInflater = LayoutInflater.from(context);
mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
+ mStableLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, null);
mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
mAnimationHelper = new TaskStackAnimationHelper(context, this);
@@ -255,41 +275,6 @@
}
}
- /**
- * Called only if we are resuming Recents.
- */
- void onResume(boolean isResumingFromVisible) {
- if (!isResumingFromVisible) {
- // Reset the focused task
- resetFocusedTask(getFocusedTask());
- }
-
- // Reset the state of each of the task views
- List<TaskView> taskViews = new ArrayList<>();
- taskViews.addAll(getTaskViews());
- taskViews.addAll(mViewPool.getViews());
- for (int i = taskViews.size() - 1; i >= 0; i--) {
- taskViews.get(i).onResume(isResumingFromVisible);
- }
-
- // Reset the stack state
- readSystemFlags();
- mTaskViewsClipDirty = true;
- mEnterAnimationComplete = false;
- mUIDozeTrigger.stopDozing();
- if (isResumingFromVisible) {
- // Animate in the freeform workspace
- int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
- animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
- Interpolators.FAST_OUT_SLOW_IN));
- } else {
- mStackScroller.reset();
- mLayoutAlgorithm.reset();
- mAwaitingFirstLayout = true;
- requestLayout();
- }
- }
-
@Override
protected void onAttachedToWindow() {
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
@@ -304,34 +289,54 @@
}
/**
+ * Called from RecentsActivity when it is relaunched.
+ */
+ void onReload(boolean isResumingFromVisible) {
+ if (!isResumingFromVisible) {
+ // Reset the focused task
+ resetFocusedTask(getFocusedTask());
+ }
+
+ // Reset the state of each of the task views
+ List<TaskView> taskViews = new ArrayList<>();
+ taskViews.addAll(getTaskViews());
+ taskViews.addAll(mViewPool.getViews());
+ for (int i = taskViews.size() - 1; i >= 0; i--) {
+ taskViews.get(i).onReload(isResumingFromVisible);
+ }
+
+ // Reset the stack state
+ readSystemFlags();
+ mTaskViewsClipDirty = true;
+ mEnterAnimationComplete = false;
+ mUIDozeTrigger.stopDozing();
+ if (isResumingFromVisible) {
+ // Animate in the freeform workspace
+ int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
+ animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
+ Interpolators.FAST_OUT_SLOW_IN));
+ } else {
+ mStackScroller.reset();
+ mStableLayoutAlgorithm.reset();
+ mLayoutAlgorithm.reset();
+ }
+
+ // Since we always animate to the same place in (the initial state), always reset the stack
+ // to the initial state when resuming
+ mAwaitingFirstLayout = true;
+ mInitialState = INITIAL_STATE_UPDATE_ALL;
+ requestLayout();
+ }
+
+ /**
* Sets the stack tasks of this TaskStackView from the given TaskStack.
*/
- public void setTasks(TaskStack stack, boolean notifyStackChanges, boolean relayoutTaskStack,
- boolean multiWindowChange) {
+ public void setTasks(TaskStack stack, boolean allowNotifyStackChanges) {
boolean isInitialized = mLayoutAlgorithm.isInitialized();
+ // Only notify if we are already initialized, otherwise, everything will pick up all the
+ // new and old tasks when we next layout
mStack.setTasks(getContext(), stack.computeAllTasksList(),
- notifyStackChanges && isInitialized);
- if (isInitialized) {
- // Only update the layout if we are notifying, otherwise, we will update it in the next
- // measure/layout pass
- updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
- if (!multiWindowChange) {
- updateToInitialState();
- }
-
- if (relayoutTaskStack) {
- relayoutTaskViews(AnimationProps.IMMEDIATE);
-
- // Rebind all the task views. This will not trigger new resources to be loaded
- // unless they have actually changed
- List<TaskView> taskViews = getTaskViews();
- int taskViewCount = taskViews.size();
- for (int i = 0; i < taskViewCount; i++) {
- TaskView tv = taskViews.get(i);
- bindTaskView(tv, tv.getTask());
- }
- }
- }
+ allowNotifyStackChanges && isInitialized);
}
/** Returns the task stack. */
@@ -342,8 +347,10 @@
/**
* Updates this TaskStackView to the initial state.
*/
- public void updateToInitialState() {
- mStackScroller.setStackScrollToInitialState();
+ public void updateToInitialState(boolean scrollToInitialState) {
+ if (scrollToInitialState) {
+ mStackScroller.setStackScrollToInitialState();
+ }
mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
}
@@ -771,8 +778,6 @@
* Updates the clip for each of the task views from back to front.
*/
private void clipTaskViews() {
- RecentsConfiguration config = Recents.getConfiguration();
-
// Update the clip on each task child
List<TaskView> taskViews = getTaskViews();
TaskView tmpTv = null;
@@ -1177,6 +1182,7 @@
*/
public void setSystemInsets(Rect systemInsets) {
if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
+ mStableLayoutAlgorithm.setSystemInsets(systemInsets);
mLayoutAlgorithm.setSystemInsets(systemInsets);
requestLayout();
}
@@ -1205,17 +1211,17 @@
}
// Compute the rects in the stack algorithm
+ mStableLayoutAlgorithm.initialize(mStableWindowRect, mStableStackBounds,
+ TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
// If this is the first layout, then scroll to the front of the stack, then update the
// TaskViews with the stack so that we can lay them out
- // TODO: The second check is a workaround for wacky layouts that we get while docking via
- // long pressing the recents button
- if (mAwaitingFirstLayout ||
- (mStackScroller.getStackScroll() == mLayoutAlgorithm.mInitialScrollP)) {
- updateToInitialState();
+ if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE) {
+ updateToInitialState(mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY);
+ mInitialState = INITIAL_STATE_UPDATE_NONE;
}
// Rebind all the views, including the ignore ones
@@ -1244,12 +1250,11 @@
} else {
mTmpRect.setEmpty();
}
+ Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
tv.measure(
- MeasureSpec.makeMeasureSpec(
- mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
+ MeasureSpec.makeMeasureSpec(taskRect.width() + mTmpRect.left + mTmpRect.right,
MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(
- mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
+ MeasureSpec.makeMeasureSpec(taskRect.height() + mTmpRect.top + mTmpRect.bottom,
MeasureSpec.EXACTLY));
}
@@ -1288,7 +1293,7 @@
} else {
mTmpRect.setEmpty();
}
- Rect taskRect = mLayoutAlgorithm.mTaskRect;
+ Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
tv.cancelTransformAnimation();
tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
@@ -1439,6 +1444,22 @@
}
}
+ @Override
+ public void onStackTasksUpdated(TaskStack stack) {
+ // Update the layout and immediately layout
+ updateLayoutAlgorithm(false /* boundScroll */);
+ relayoutTaskViews(AnimationProps.IMMEDIATE);
+
+ // Rebind all the task views. This will not trigger new resources to be loaded
+ // unless they have actually changed
+ List<TaskView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ bindTaskView(tv, tv.getTask());
+ }
+ }
+
/**** ViewPoolConsumer Implementation ****/
@Override
@@ -1911,9 +1932,25 @@
}
public final void onBusEvent(ConfigurationChangedEvent event) {
+ mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
- mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
- TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+
+ // Notify the task views of the configuration change so they can reload their resources
+ if (!event.fromMultiWindow) {
+ mTmpTaskViews.clear();
+ mTmpTaskViews.addAll(getTaskViews());
+ mTmpTaskViews.addAll(mViewPool.getViews());
+ int taskViewCount = mTmpTaskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ mTmpTaskViews.get(i).onConfigurationChanged();
+ }
+ }
+
+ // Trigger a new layout and scroll to the initial state
+ mInitialState = event.fromMultiWindow
+ ? INITIAL_STATE_UPDATE_ALL
+ : INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+ requestLayout();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 0c47b13..c085d80 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -24,6 +24,7 @@
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Paint;
@@ -191,15 +192,15 @@
mCb = cb;
}
- /** Resets this TaskView for reuse. */
- void onResume(boolean isResumingFromVisible) {
+ /**
+ * Called from RecentsActivity when it is relaunched.
+ */
+ void onReload(boolean isResumingFromVisible) {
resetNoUserInteractionState();
readSystemFlags();
if (!isResumingFromVisible) {
resetViewProperties();
- setClipViewInStack(false);
}
- setCallbacks(null);
}
/** Gets the task */
@@ -237,6 +238,13 @@
mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
}
+ /**
+ * Update the task view when the configuration changes.
+ */
+ void onConfigurationChanged() {
+ mHeaderView.onConfigurationChanged();
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 62995a6..ddea4d9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -250,6 +250,44 @@
mFocusTimerIndicatorStub = (ViewStub) findViewById(R.id.focus_timer_indicator_stub);
mAppOverlayViewStub = (ViewStub) findViewById(R.id.app_overlay_stub);
+ onConfigurationChanged();
+ }
+
+ /**
+ * Programmatically sets the layout params for a header bar layout. This is necessary because
+ * we can't get resources based on the current configuration, but instead need to get them
+ * based on the device configuration.
+ */
+ private void updateLayoutParams(View icon, View title, View secondaryButton, View button) {
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, mHeaderBarHeight, Gravity.TOP);
+ setLayoutParams(lp);
+ lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.START);
+ icon.setLayoutParams(lp);
+ lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
+ lp.setMarginStart(mHeaderBarHeight);
+ lp.rightMargin = mMoveTaskButton != null
+ ? 2 * mHeaderBarHeight
+ : mHeaderBarHeight;
+ title.setLayoutParams(lp);
+ if (secondaryButton != null) {
+ lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
+ lp.setMarginEnd(mHeaderBarHeight);
+ secondaryButton.setLayoutParams(lp);
+ secondaryButton.setPadding(mHeaderButtonPadding, mHeaderButtonPadding,
+ mHeaderButtonPadding, mHeaderButtonPadding);
+ }
+ lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
+ button.setLayoutParams(lp);
+ button.setPadding(mHeaderButtonPadding, mHeaderButtonPadding, mHeaderButtonPadding,
+ mHeaderButtonPadding);
+ }
+
+ /**
+ * Update the header view when the configuration changes.
+ */
+ void onConfigurationChanged() {
// Update the dimensions of everything in the header. We do this because we need to use
// resources for the display, and not the current configuration.
Resources res = getResources();
@@ -269,37 +307,9 @@
R.dimen.recents_task_view_header_button_padding_tablet_land);
updateLayoutParams(mIconView, findViewById(R.id.title_container), mMoveTaskButton,
mDismissButton);
- }
-
- /**
- * Programmatically sets the layout params for a header bar layout. This is necessary because
- * we can't get resources based on the current configuration, but instead need to get them
- * based on the device configuration.
- */
- private void updateLayoutParams(View icon, View title, View secondaryButton, View button) {
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, mHeaderBarHeight, Gravity.TOP);
- setLayoutParams(lp);
- lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.START);
- icon.setLayoutParams(lp);
- lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
- lp.leftMargin = mHeaderBarHeight;
- lp.rightMargin = mMoveTaskButton != null
- ? 2 * mHeaderBarHeight
- : mHeaderBarHeight;
- title.setLayoutParams(lp);
- if (secondaryButton != null) {
- lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
- lp.rightMargin = mHeaderBarHeight;
- secondaryButton.setLayoutParams(lp);
- secondaryButton.setPadding(mHeaderButtonPadding, mHeaderButtonPadding,
- mHeaderButtonPadding, mHeaderButtonPadding);
+ if (mAppOverlayView != null) {
+ updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
}
- lp = new FrameLayout.LayoutParams(mHeaderBarHeight, mHeaderBarHeight, Gravity.END);
- button.setLayoutParams(lp);
- button.setPadding(mHeaderButtonPadding, mHeaderButtonPadding, mHeaderButtonPadding,
- mHeaderButtonPadding);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index e9c09ac..3eeabc7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -243,11 +243,6 @@
public void updateThumbnailScale() {
mThumbnailScale = 1f;
if (mBitmapShader != null) {
-
- if (mThumbnailInfo != null) {
- System.out.println(mTask.title + " bounds: " + mThumbnailInfo.taskWidth + "x" + mThumbnailInfo.taskHeight + ", " + mThumbnailInfo.screenOrientation);
- }
-
// We consider this a stack task if it is not freeform (ie. has no bounds) or has been
// dragged into the stack from the freeform workspace
boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index dd59fac..e8cf126 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -41,6 +41,7 @@
private DockDividerVisibilityListener mDockDividerVisibilityListener;
private boolean mVisible = false;
private boolean mMinimized = false;
+ private ForcedResizableInfoActivityController mForcedResizableController;
@Override
public void start() {
@@ -52,6 +53,7 @@
mDockDividerVisibilityListener = new DockDividerVisibilityListener();
SystemServicesProxy ssp = Recents.getSystemServices();
ssp.registerDockedStackListener(mDockDividerVisibilityListener);
+ mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
}
@Override
@@ -117,6 +119,15 @@
});
}
+ private void notifyDockedStackExistsChanged(final boolean exists) {
+ mView.post(new Runnable() {
+ @Override
+ public void run() {
+ mForcedResizableController.notifyDockedStackExistsChanged(exists);
+ }
+ });
+ }
+
class DockDividerVisibilityListener extends IDockedStackListener.Stub {
@Override
@@ -126,6 +137,7 @@
@Override
public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
+ notifyDockedStackExistsChanged(exists);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 132c09f..7a933cd 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -66,6 +66,8 @@
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.stackdivider.events.StartedDragingEvent;
+import com.android.systemui.stackdivider.events.StoppedDragingEvent;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
@@ -81,6 +83,7 @@
private static final String TAG = "DividerView";
private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
+ private static final boolean SWAPPING_ENABLED = false;
/**
* How much the background gets scaled when we are in the minimized dock state.
@@ -168,6 +171,13 @@
}
};
+ private final Runnable mResetBackgroundRunnable = new Runnable() {
+ @Override
+ public void run() {
+ resetBackground();
+ }
+ };
+
public DividerView(Context context) {
super(context);
}
@@ -211,12 +221,14 @@
mGestureDetector = new GestureDetector(mContext, new SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
- updateDockSide();
- SystemServicesProxy ssp = Recents.getSystemServices();
- if (mDockSide != WindowManager.DOCKED_INVALID
- && !ssp.isRecentsTopMost(ssp.getTopMostTask(), null /* isTopHome */)) {
- mWindowManagerProxy.swapTasks();
- return true;
+ if (SWAPPING_ENABLED) {
+ updateDockSide();
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (mDockSide != WindowManager.DOCKED_INVALID
+ && !ssp.isRecentsTopMost(ssp.getTopMostTask(), null /* isTopHome */)) {
+ mWindowManagerProxy.swapTasks();
+ return true;
+ }
}
return false;
}
@@ -281,6 +293,7 @@
mWindowManager.setSlippery(false);
liftBackground();
}
+ EventBus.getDefault().send(new StartedDragingEvent());
return mDockSide != WindowManager.DOCKED_INVALID;
}
@@ -380,13 +393,6 @@
x = (int) event.getRawX();
y = (int) event.getRawY();
- if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
- int position = calculatePosition(x, y);
- SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
- 0 /* velocity */, false /* hardDismiss */);
- resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
- }
-
mVelocityTracker.computeCurrentVelocity(1000);
int position = calculatePosition(x, y);
stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
@@ -439,6 +445,7 @@
mDockSide = WindowManager.DOCKED_INVALID;
mCurrentAnimator = null;
mEntranceAnimationRunning = false;
+ EventBus.getDefault().send(new StoppedDragingEvent());
}
});
mCurrentAnimator = anim;
@@ -519,15 +526,17 @@
public void setMinimizedDockStack(boolean minimized) {
updateDockSide();
mHandle.setAlpha(minimized ? 0f : 1f);
- if (mDockSide == WindowManager.DOCKED_TOP) {
+ if (!minimized) {
+ resetBackground();
+ } else if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
- mBackground.setScaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
} else if (mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_RIGHT) {
mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
? 0
: mBackground.getWidth());
- mBackground.setScaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
}
}
@@ -550,12 +559,22 @@
mBackground.animate()
.scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
}
+ if (!minimized) {
+ mBackground.animate().withEndAction(mResetBackgroundRunnable);
+ }
mBackground.animate()
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(animDuration)
.start();
}
+ private void resetBackground() {
+ mBackground.setPivotX(mBackground.getWidth() / 2);
+ mBackground.setPivotY(mBackground.getHeight() / 2);
+ mBackground.setScaleX(1f);
+ mBackground.setScaleY(1f);
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -730,21 +749,22 @@
mSnapAlgorithm.calculateDismissingFraction(position)));
SnapTarget dismissTarget = null;
SnapTarget splitTarget = null;
- if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
- || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
+ int start = 0;
+ if (position <= mSnapAlgorithm.getLastSplitTarget().position
&& dockSideTopLeft(dockSide)) {
dismissTarget = mSnapAlgorithm.getDismissStartTarget();
splitTarget = mSnapAlgorithm.getFirstSplitTarget();
- } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
- || snapTarget == mSnapAlgorithm.getLastSplitTarget())
+ start = taskPosition;
+ } else if (position >= mSnapAlgorithm.getLastSplitTarget().position
&& dockSideBottomRight(dockSide)) {
dismissTarget = mSnapAlgorithm.getDismissEndTarget();
splitTarget = mSnapAlgorithm.getLastSplitTarget();
+ start = splitTarget.position;
}
if (dismissTarget != null && fraction > 0f
&& isDismissing(splitTarget, position, dockSide)) {
fraction = calculateParallaxDismissingFraction(fraction, dockSide);
- int offsetPosition = (int) (taskPosition +
+ int offsetPosition = (int) (start +
fraction * (dismissTarget.position - splitTarget.position));
int width = taskRect.width();
int height = taskRect.height();
@@ -792,11 +812,12 @@
}
private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
- if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
- (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
+ if ((dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide))
+ || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END
+ && dockSideBottomRight(mDockSide))) {
return StackId.DOCKED_STACK_ID;
} else {
- return StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+ return StackId.HOME_STACK_ID;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
new file mode 100644
index 0000000..f728dab
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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.systemui.stackdivider;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+
+import com.android.systemui.R;
+
+/**
+ * Translucent activity that gets started on top of a task in multi-window to inform the user that
+ * we forced the activity below to be resizable.
+ */
+public class ForcedResizableInfoActivity extends Activity implements OnTouchListener {
+
+ private static final long DISMISS_DELAY = 2500;
+
+ private final Runnable mFinishRunnable = new Runnable() {
+ @Override
+ public void run() {
+ finish();
+ }
+ };
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.forced_resizable_activity);
+ getWindow().getDecorView().setOnTouchListener(this);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ getWindow().getDecorView().postDelayed(mFinishRunnable, DISMISS_DELAY);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ finish();
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ finish();
+ return true;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ finish();
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
new file mode 100644
index 0000000..9b56037
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016 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.systemui.stackdivider;
+
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
+import com.android.systemui.recents.events.activity.ForcedResizableEvent;
+import com.android.systemui.stackdivider.events.StartedDragingEvent;
+import com.android.systemui.stackdivider.events.StoppedDragingEvent;
+
+/**
+ * Controller that decides when to show the {@link ForcedResizableInfoActivity}.
+ */
+public class ForcedResizableInfoActivityController {
+
+ private static final String SELF_PACKAGE_NAME = "com.android.systemui";
+
+ private static final int TIMEOUT = 1000;
+ private final Context mContext;
+ private final Handler mHandler = new Handler();
+ private final ArraySet<Integer> mPendingTaskIds = new ArraySet<>();
+ private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
+ private boolean mDividerDraging;
+
+ private final Runnable mTimeoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ showPending();
+ }
+ };
+
+ public ForcedResizableInfoActivityController(Context context) {
+ mContext = context;
+ EventBus.getDefault().register(this);
+ }
+
+ public void notifyDockedStackExistsChanged(boolean exists) {
+ if (!exists) {
+ mPackagesShownInSession.clear();
+ }
+ }
+
+ public final void onBusEvent(ForcedResizableEvent forcedResizableEvent) {
+ if (debounce(forcedResizableEvent.packageName)) {
+ return;
+ }
+ mPendingTaskIds.add(forcedResizableEvent.taskId);
+ postTimeout();
+ }
+
+ public final void onBusEvent(AppTransitionFinishedEvent event) {
+ if (!mDividerDraging) {
+ showPending();
+ }
+ }
+
+ public final void onBusEvent(StartedDragingEvent event) {
+ mDividerDraging = true;
+ mHandler.removeCallbacks(mTimeoutRunnable);
+ }
+
+ public final void onBusEvent(StoppedDragingEvent event) {
+ mDividerDraging = false;
+ showPending();
+ }
+
+ private void showPending() {
+ mHandler.removeCallbacks(mTimeoutRunnable);
+ for (int i = mPendingTaskIds.size() - 1; i >= 0; i--) {
+ Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class);
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
+ mContext.startActivity(intent, options.toBundle());
+ }
+ mPendingTaskIds.clear();
+ }
+
+ private void postTimeout() {
+ mHandler.removeCallbacks(mTimeoutRunnable);
+ mHandler.postDelayed(mTimeoutRunnable, TIMEOUT);
+ }
+
+ private boolean debounce(String packageName) {
+ if (packageName == null) {
+ return false;
+ }
+
+ // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that
+ // triggers another notification. So ignore our own activity.
+ if (SELF_PACKAGE_NAME.equals(packageName)) {
+ return true;
+ }
+ boolean debounce = mPackagesShownInSession.contains(packageName);
+ mPackagesShownInSession.add(packageName);
+ return debounce;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
new file mode 100644
index 0000000..5d19851
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StartedDragingEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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.systemui.stackdivider.events;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when the divider is being draged either manually or by an animation.
+ */
+public class StartedDragingEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
new file mode 100644
index 0000000..c50d6d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/events/StoppedDragingEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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.systemui.stackdivider.events;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when the divider isn't draging anymore.
+ */
+public class StoppedDragingEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 0ffab5b..d00e8ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -73,6 +73,7 @@
private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT;
private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT;
private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT;
+ private static final int MSG_APP_TRANSITION_FINISHED = 31 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -117,6 +118,7 @@
public void appTransitionPending();
public void appTransitionCancelled();
public void appTransitionStarting(long startTime, long duration);
+ public void appTransitionFinished();
public void showAssistDisclosure();
public void startAssist(Bundle args);
public void onCameraLaunchGestureDetected(int source);
@@ -324,6 +326,14 @@
}
}
+ @Override
+ public void appTransitionFinished() {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_APP_TRANSITION_FINISHED);
+ mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
+ }
+ }
+
public void showAssistDisclosure() {
synchronized (mLock) {
mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
@@ -452,6 +462,9 @@
Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
mCallbacks.appTransitionStarting(data.first, data.second);
break;
+ case MSG_APP_TRANSITION_FINISHED:
+ mCallbacks.appTransitionFinished();
+ break;
case MSG_ASSIST_DISCLOSURE:
mCallbacks.showAssistDisclosure();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 726aed3..4add3cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -24,6 +24,7 @@
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteException;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewStub;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9b1f338..7ae87e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -120,6 +120,7 @@
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
@@ -4310,6 +4311,7 @@
@Override
public void appTransitionCancelled() {
mIconController.appTransitionCancelled();
+ EventBus.getDefault().send(new AppTransitionFinishedEvent());
}
@Override
@@ -4326,6 +4328,11 @@
}
@Override
+ public void appTransitionFinished() {
+ EventBus.getDefault().send(new AppTransitionFinishedEvent());
+ }
+
+ @Override
public void onCameraLaunchGestureDetected(int source) {
mLastCameraLaunchSource = source;
if (mStartedGoingToSleep) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2524e1a..f9bb5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -171,6 +171,10 @@
}
@Override
+ public void appTransitionFinished() {
+ }
+
+ @Override
public void onCameraLaunchGestureDetected(int source) {
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e710ded..e3dac28 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1812,6 +1812,87 @@
return mKeyEventDispatcher;
}
+ /**
+ * Enables accessibility service specified by {@param componentName} for the {@param userId}.
+ */
+ public void enableAccessibilityService(ComponentName componentName, int userId) {
+ synchronized(mLock) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("only SYSTEM can call enableAccessibilityService.");
+ }
+
+ SettingsStringHelper settingsHelper = new SettingsStringHelper(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+ settingsHelper.addService(componentName);
+ settingsHelper.writeToSettings();
+
+ UserState userState = getUserStateLocked(userId);
+ if (userState.mEnabledServices.add(componentName)) {
+ onUserStateChangedLocked(userState);
+ }
+ }
+ }
+
+ /**
+ * Disables accessibility service specified by {@param componentName} for the {@param userId}.
+ */
+ public void disableAccessibilityService(ComponentName componentName, int userId) {
+ synchronized(mLock) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("only SYSTEM can call disableAccessibility");
+ }
+
+ SettingsStringHelper settingsHelper = new SettingsStringHelper(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+ settingsHelper.deleteService(componentName);
+ settingsHelper.writeToSettings();
+
+ UserState userState = getUserStateLocked(userId);
+ if (userState.mEnabledServices.remove(componentName)) {
+ onUserStateChangedLocked(userState);
+ }
+ }
+ }
+
+ private class SettingsStringHelper {
+ private static final String SETTINGS_DELIMITER = ":";
+ private ContentResolver mContentResolver;
+ private final String mSettingsName;
+ private Set<String> mServices;
+ private final int mUserId;
+
+ public SettingsStringHelper(String name, int userId) {
+ mUserId = userId;
+ mSettingsName = name;
+ mContentResolver = mContext.getContentResolver();
+ String servicesString = Settings.Secure.getStringForUser(
+ mContentResolver, mSettingsName, userId);
+ mServices = new HashSet();
+ if (!TextUtils.isEmpty(servicesString)) {
+ final TextUtils.SimpleStringSplitter colonSplitter =
+ new TextUtils.SimpleStringSplitter(SETTINGS_DELIMITER.charAt(0));
+ colonSplitter.setString(servicesString);
+ while (colonSplitter.hasNext()) {
+ final String serviceName = colonSplitter.next();
+ mServices.add(serviceName);
+ }
+ }
+ }
+
+ public void addService(ComponentName component) {
+ mServices.add(component.flattenToString());
+ }
+
+ public void deleteService(ComponentName component) {
+ mServices.remove(component.flattenToString());
+ }
+
+ public void writeToSettings() {
+ Settings.Secure.putStringForUser(mContentResolver, mSettingsName,
+ TextUtils.join(SETTINGS_DELIMITER, mServices), mUserId);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 898d5b73..e042483 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -215,7 +215,7 @@
// Ongoing notification
private NotificationManager mNotificationManager;
private KeyguardManager mKeyguardManager;
- private StatusBarManagerService mStatusBar;
+ private @Nullable StatusBarManagerService mStatusBar;
private Notification.Builder mImeSwitcherNotification;
private PendingIntent mImeSwitchPendingIntent;
private boolean mShowOngoingImeSwitcherForPhones;
@@ -1070,7 +1070,9 @@
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
mNotificationManager = mContext.getSystemService(NotificationManager.class);
mStatusBar = statusBar;
- statusBar.setIconVisibility(mSlotIme, false);
+ if (mStatusBar != null) {
+ mStatusBar.setIconVisibility(mSlotIme, false);
+ }
updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index c1a352c..c6d536d 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -209,9 +209,12 @@
/** Set of interfaces with active alerts. */
@GuardedBy("mQuotaLock")
private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
- /** Set of UIDs with active reject rules. */
+ /** Set of UIDs blacklisted on metered networks. */
@GuardedBy("mQuotaLock")
- private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
+ private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray();
+ /** Set of UIDs whitelisted on metered networks. */
+ @GuardedBy("mQuotaLock")
+ private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
/** Set of UIDs with cleartext penalties. */
@GuardedBy("mQuotaLock")
private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
@@ -240,6 +243,9 @@
@GuardedBy("mQuotaLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
+ @GuardedBy("mQuotaLock")
+ private boolean mDataSaverMode;
+
private Object mIdleTimerLock = new Object();
/** Set of interfaces with active idle timers. */
private static class IdleTimerParams {
@@ -583,6 +589,9 @@
// push any existing quota or UID rules
synchronized (mQuotaLock) {
+
+ setDataSaverModeEnabled(mDataSaverMode);
+
int size = mActiveQuotas.size();
if (size > 0) {
if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules");
@@ -603,13 +612,25 @@
}
}
- size = mUidRejectOnQuota.size();
+ size = mUidRejectOnMetered.size();
if (size > 0) {
- if (DBG) Slog.d(TAG, "Pushing " + size + " active UID rules");
- final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
- mUidRejectOnQuota = new SparseBooleanArray();
+ if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered whitelist rules");
+ final SparseBooleanArray uidRejectOnQuota = mUidRejectOnMetered;
+ mUidRejectOnMetered = new SparseBooleanArray();
for (int i = 0; i < uidRejectOnQuota.size(); i++) {
- setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
+ setUidMeteredNetworkBlacklist(uidRejectOnQuota.keyAt(i),
+ uidRejectOnQuota.valueAt(i));
+ }
+ }
+
+ size = mUidAllowOnMetered.size();
+ if (size > 0) {
+ if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered blacklist rules");
+ final SparseBooleanArray uidAcceptOnQuota = mUidAllowOnMetered;
+ mUidAllowOnMetered = new SparseBooleanArray();
+ for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
+ setUidMeteredNetworkWhitelist(uidAcceptOnQuota.keyAt(i),
+ uidAcceptOnQuota.valueAt(i));
}
}
@@ -723,6 +744,7 @@
private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
@Override
public void onDaemonConnected() {
+ Slog.i(TAG, "onDaemonConnected()");
// event is dispatched from internal NDC thread, so we prepare the
// daemon back on main thread.
if (mConnectedSignal != null) {
@@ -1683,28 +1705,30 @@
}
}
- @Override
- public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ private void setUidOnMeteredNetworkList(SparseBooleanArray quotaList, int uid,
+ boolean blacklist, boolean enable) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
// silently discard when control disabled
// TODO: eventually migrate to be always enabled
if (!mBandwidthControlEnabled) return;
+ final String chain = blacklist ? "naughtyapps" : "niceapps";
+ final String suffix = enable ? "add" : "remove";
+
synchronized (mQuotaLock) {
- final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
- if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
+ final boolean oldEnable = quotaList.get(uid, false);
+ if (oldEnable == enable) {
// TODO: eventually consider throwing
return;
}
try {
- mConnector.execute("bandwidth",
- rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
- if (rejectOnQuotaInterfaces) {
- mUidRejectOnQuota.put(uid, true);
+ mConnector.execute("bandwidth", suffix + chain, uid);
+ if (enable) {
+ quotaList.put(uid, true);
} else {
- mUidRejectOnQuota.delete(uid);
+ quotaList.delete(uid);
}
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
@@ -1713,6 +1737,39 @@
}
@Override
+ public void setUidMeteredNetworkBlacklist(int uid, boolean enable) {
+ setUidOnMeteredNetworkList(mUidRejectOnMetered, uid, true, enable);
+ }
+
+ @Override
+ public void setUidMeteredNetworkWhitelist(int uid, boolean enable) {
+ setUidOnMeteredNetworkList(mUidAllowOnMetered, uid, false, enable);
+ }
+
+ @Override
+ public boolean setDataSaverModeEnabled(boolean enable) {
+ if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
+ synchronized (mQuotaLock) {
+ if (mDataSaverMode == enable) {
+ Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
+ return true;
+ }
+ try {
+ final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
+ if (changed) {
+ mDataSaverMode = enable;
+ } else {
+ Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed");
+ }
+ return changed;
+ } catch (RemoteException e) {
+ Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
+ return false;
+ }
+ }
+ }
+
+ @Override
public void setUidCleartextNetworkPolicy(int uid, int policy) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -2206,29 +2263,22 @@
synchronized (mQuotaLock) {
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
- }
-
- synchronized (mUidRejectOnQuota) {
- pw.print("UID reject on quota ifaces: [");
- final int size = mUidRejectOnQuota.size();
- for (int i = 0; i < size; i++) {
- pw.print(mUidRejectOnQuota.keyAt(i));
- if (i < size - 1) pw.print(",");
- }
- pw.println("]");
+ pw.print("Data saver mode: "); pw.println(mDataSaverMode);
+ dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered);
+ dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered);
}
synchronized (mUidFirewallRules) {
dumpUidFirewallRule(pw, "", mUidFirewallRules);
}
- pw.println("UID firewall standby chain enabled: " +
+ pw.print("UID firewall standby chain enabled: "); pw.println(
mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
synchronized (mUidFirewallStandbyRules) {
dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
}
- pw.println("UID firewall dozable chain enabled: " +
+ pw.print("UID firewall dozable chain enabled: "); pw.println(
mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
synchronized (mUidFirewallDozableRules) {
dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
@@ -2252,6 +2302,29 @@
}
pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
+ pw.print("Netd service status: " );
+ if (mNetdService == null) {
+ pw.println("disconnected");
+ } else {
+ try {
+ final boolean alive = mNetdService.isAlive();
+ pw.println(alive ? "alive": "dead");
+ } catch (RemoteException e) {
+ pw.println("unreachable");
+ }
+ }
+ }
+
+ private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) {
+ pw.print("UID bandwith control ");
+ pw.print(name);
+ pw.print(" rule: [");
+ final int size = list.size();
+ for (int i = 0; i < size; i++) {
+ pw.print(list.keyAt(i));
+ if (i < size - 1) pw.print(",");
+ }
+ pw.println("]");
}
private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1abb5ff..3d13715 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -55,7 +55,6 @@
import com.android.server.pm.Installer;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
-import com.android.server.wm.AppTransition;
import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
@@ -103,7 +102,6 @@
import android.app.ProfilerInfo;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
-import android.app.admin.IDevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.IBackupManager;
@@ -355,6 +353,7 @@
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
+import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
@@ -1471,6 +1470,7 @@
static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 65;
static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
+ static final int NOTIFY_FORCED_RESIZABLE_MSG = 67;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2019,6 +2019,21 @@
}
break;
}
+ case NOTIFY_FORCED_RESIZABLE_MSG: {
+ synchronized (ActivityManagerService.this) {
+ for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
+ try {
+ // Make a one-way callback to the listener
+ mTaskStackListeners.getBroadcastItem(i).onActivityForcedResizable(
+ (String) msg.obj, msg.arg1);
+ } catch (RemoteException e){
+ // Handled by the RemoteCallbackList
+ }
+ }
+ mTaskStackListeners.finishBroadcast();
+ }
+ break;
+ }
case NOTIFY_CLEARTEXT_NETWORK_MSG: {
final int uid = msg.arg1;
final byte[] firstPacket = (byte[]) msg.obj;
@@ -4479,63 +4494,14 @@
}
final long origId = Binder.clearCallingIdentity();
try {
- return startActivityFromRecentsInner(taskId, bOptions);
+ synchronized (this) {
+ return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
- final TaskRecord task;
- final int callingUid;
- final String callingPackage;
- final Intent intent;
- final int userId;
- synchronized (this) {
- final ActivityOptions activityOptions = (bOptions != null)
- ? new ActivityOptions(bOptions) : null;
- final int launchStackId = (activityOptions != null)
- ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
-
- if (launchStackId == HOME_STACK_ID) {
- throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
- + taskId + " can't be launch in the home stack.");
- }
- task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
- if (task == null) {
- throw new IllegalArgumentException(
- "startActivityFromRecentsInner: Task " + taskId + " not found.");
- }
-
- if (launchStackId != INVALID_STACK_ID) {
- if (launchStackId == DOCKED_STACK_ID && activityOptions != null) {
- mWindowManager.setDockedStackCreateState(
- activityOptions.getDockCreateMode(), null /* initialBounds */);
- }
- if (task.stack.mStackId != launchStackId) {
- mStackSupervisor.moveTaskToStackLocked(
- taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
- ANIMATE);
- }
- }
-
- // If the user must confirm credentials (e.g. when first launching a work app and the
- // Work Challenge is present) let startActivityInPackage handle the intercepting.
- if (!mUserController.shouldConfirmCredentials(task.userId)
- && task.getRootActivity() != null) {
- moveTaskToFrontLocked(task.taskId, 0, bOptions);
- return ActivityManager.START_TASK_TO_FRONT;
- }
- callingUid = task.mCallingUid;
- callingPackage = task.mCallingPackage;
- intent = task.intent;
- intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
- userId = task.userId;
- }
- return startActivityInPackage(callingUid, callingPackage, intent, null, null, null, 0, 0,
- bOptions, userId, null, task);
- }
-
final int startActivityInPackage(int uid, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
@@ -11426,10 +11392,12 @@
// Get the focused task before launching launcher.
if (mUserController.isLockScreenDisabled(currentUserId)) {
+
// If there is no device lock, we will show the profile's credential page.
// startActivityFromRecentsInner is intercepted and will forward user to it.
if (mFocusedActivity != null) {
- startActivityFromRecentsInner(mFocusedActivity.task.taskId, null);
+ mStackSupervisor.startActivityFromRecentsInner(
+ mFocusedActivity.task.taskId, null);
}
} else {
// Showing launcher to avoid user entering credential twice.
@@ -21033,6 +21001,20 @@
mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(reason);
}
}
+
+ @Override
+ public void notifyAppTransitionFinished() {
+ synchronized (ActivityManagerService.this) {
+ mStackSupervisor.notifyAppTransitionDone();
+ }
+ }
+
+ @Override
+ public void notifyAppTransitionCancelled() {
+ synchronized (ActivityManagerService.this) {
+ mStackSupervisor.notifyAppTransitionDone();
+ }
+ }
}
private final class SleepTokenImpl extends SleepToken {
@@ -21121,7 +21103,9 @@
// Will bring task to front if it already has a root activity.
final long origId = Binder.clearCallingIdentity();
try {
- startActivityFromRecentsInner(mTaskId, null);
+ synchronized (this) {
+ mStackSupervisor.startActivityFromRecentsInner(mTaskId, null);
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 5cb04c8..ee406da 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -258,6 +258,12 @@
// Current bounds of the stack or null if fullscreen.
Rect mBounds = null;
+ boolean mUpdateBoundsDeferred;
+ boolean mUpdateBoundsDeferredCalled;
+ final Rect mDeferredBounds = new Rect();
+ final Rect mDeferredTaskBounds = new Rect();
+ final Rect mDeferredTaskInsetBounds = new Rect();
+
long mLaunchStartTime = 0;
long mFullyDrawnStartTime = 0;
@@ -427,6 +433,57 @@
mActivityContainer.mActivityDisplay.mDisplay.getSize(out);
}
+ /**
+ * Defers updating the bounds of the stack. If the stack was resized/repositioned while
+ * deferring, the bounds will update in {@link #continueUpdateBounds()}.
+ */
+ void deferUpdateBounds() {
+ if (!mUpdateBoundsDeferred) {
+ mUpdateBoundsDeferred = true;
+ mUpdateBoundsDeferredCalled = false;
+ }
+ }
+
+ /**
+ * Continues updating bounds after updates have been deferred. If there was a resize attempt
+ * between {@link #deferUpdateBounds()} and {@link #continueUpdateBounds()}, the stack will
+ * be resized to that bounds.
+ */
+ void continueUpdateBounds() {
+ final boolean wasDeferred = mUpdateBoundsDeferred;
+ mUpdateBoundsDeferred = false;
+ if (wasDeferred && mUpdateBoundsDeferredCalled) {
+ mStackSupervisor.resizeStackUncheckedLocked(this,
+ mDeferredBounds.isEmpty() ? null : mDeferredBounds,
+ mDeferredTaskBounds.isEmpty() ? null : mDeferredTaskBounds,
+ mDeferredTaskInsetBounds.isEmpty() ? null : mDeferredTaskInsetBounds);
+ }
+ }
+
+ boolean updateBoundsAllowed(Rect bounds, Rect tempTaskBounds,
+ Rect tempTaskInsetBounds) {
+ if (!mUpdateBoundsDeferred) {
+ return true;
+ }
+ if (bounds != null) {
+ mDeferredBounds.set(bounds);
+ } else {
+ mDeferredBounds.setEmpty();
+ }
+ if (tempTaskBounds != null) {
+ mDeferredTaskBounds.set(tempTaskBounds);
+ } else {
+ mDeferredTaskBounds.setEmpty();
+ }
+ if (tempTaskInsetBounds != null) {
+ mDeferredTaskInsetBounds.set(tempTaskInsetBounds);
+ } else {
+ mDeferredTaskInsetBounds.setEmpty();
+ }
+ mUpdateBoundsDeferredCalled = true;
+ return false;
+ }
+
void setBounds(Rect bounds) {
mBounds = mFullscreen ? null : new Rect(bounds);
if (mTaskPositioner != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7def1bd..0e6d174 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -52,6 +52,7 @@
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
@@ -101,7 +102,9 @@
import java.util.Objects;
import java.util.Set;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
@@ -120,7 +123,6 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
@@ -151,6 +153,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.ANIMATE;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.am.ActivityManagerService.NOTIFY_FORCED_RESIZABLE_MSG;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
@@ -167,6 +170,7 @@
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
public final class ActivityStackSupervisor implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
@@ -423,6 +427,11 @@
boolean mAppVisibilitiesChangedSinceLastPause;
/**
+ * Set of tasks that are in resizing mode during an app transition to fill the "void".
+ */
+ private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>();
+
+ /**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
*/
@@ -1304,7 +1313,7 @@
boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
- ActivityRecord resultRecord, ActivityStack resultStack) {
+ ActivityRecord resultRecord, ActivityStack resultStack, ActivityOptions options) {
final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
callingUid);
if (startAnyPerm == PERMISSION_GRANTED) {
@@ -1358,6 +1367,19 @@
Slog.w(TAG, message);
return false;
}
+ if (options != null && options.getLaunchTaskId() != -1) {
+ final int startInTaskPerm = mService.checkPermission(START_TASKS_FROM_RECENTS,
+ callingPid, callingUid);
+ if (startInTaskPerm != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: starting " + intent.toString()
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with launchTaskId="
+ + options.getLaunchTaskId();
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
+
return true;
}
@@ -1788,6 +1810,8 @@
if (DEBUG_STACK) Slog.d(TAG_STACK,
"findTaskToMoveToFront: moved to front of stack=" + task.stack);
+
+ showNonResizeableDockToastIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId);
}
boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -1924,10 +1948,39 @@
}
}
- private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
+ void deferUpdateBounds(int stackId) {
+ final ActivityStack stack = getStack(stackId);
+ if (stack != null) {
+ stack.deferUpdateBounds();
+ }
+ }
+
+ void continueUpdateBounds(int stackId) {
+ final ActivityStack stack = getStack(stackId);
+ if (stack != null) {
+ stack.continueUpdateBounds();
+ }
+ }
+
+ void notifyAppTransitionDone() {
+ continueUpdateBounds(HOME_STACK_ID);
+ for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
+ final int taskId = mResizingTasksDuringAnimation.valueAt(i);
+ if (anyTaskForIdLocked(taskId) != null) {
+ mWindowManager.setTaskDockedResizing(taskId, false);
+ }
+ }
+ mResizingTasksDuringAnimation.clear();
+ }
+
+ void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
Rect tempTaskInsetBounds) {
bounds = TaskRecord.validateBounds(bounds);
+ if (!stack.updateBoundsAllowed(bounds, tempTaskBounds, tempTaskInsetBounds)) {
+ return;
+ }
+
mTmpBounds.clear();
mTmpConfigs.clear();
mTmpInsetBounds.clear();
@@ -3309,10 +3362,14 @@
return;
}
- if (!task.canGoInDockedStack() || task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
- // Display warning toast if we tried to put a non-dockable task in the docked stack or
- // the task was forced to be resizable by the system.
+ if (!task.canGoInDockedStack()) {
+ // Display a warning toast that we tried to put a non-dockable task in the docked stack.
mWindowManager.scheduleShowNonResizeableDockToast(task.taskId);
+ } else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
+ String packageName = task.getTopActivity() != null
+ ? task.getTopActivity().appInfo.packageName : null;
+ mService.mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, task.taskId, 0,
+ packageName).sendToTarget();
}
}
@@ -4129,4 +4186,80 @@
throw new IllegalStateException("Failed to find a stack behind stack=" + stack
+ " in=" + stacks);
}
+
+ /**
+ * Puts a task into resizing mode during the next app transition.
+ *
+ * @param taskId the id of the task to put into resizing mode
+ */
+ private void setResizingDuringAnimation(int taskId) {
+ mResizingTasksDuringAnimation.add(taskId);
+ mWindowManager.setTaskDockedResizing(taskId, true);
+ }
+
+ final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
+ final TaskRecord task;
+ final int callingUid;
+ final String callingPackage;
+ final Intent intent;
+ final int userId;
+ final ActivityOptions activityOptions = (bOptions != null)
+ ? new ActivityOptions(bOptions) : null;
+ final int launchStackId = (activityOptions != null)
+ ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
+
+ if (launchStackId == HOME_STACK_ID) {
+ throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+ + taskId + " can't be launch in the home stack.");
+ }
+ task = anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
+ if (task == null) {
+ throw new IllegalArgumentException(
+ "startActivityFromRecentsInner: Task " + taskId + " not found.");
+ }
+
+ if (launchStackId != INVALID_STACK_ID) {
+ if (launchStackId == DOCKED_STACK_ID) {
+ mWindowManager.setDockedStackCreateState(
+ activityOptions.getDockCreateMode(), null /* initialBounds */);
+
+ // Defer updating the stack in which recents is until the app transition is done, to
+ // not run into issues where we still need to draw the task in recents but the
+ // docked stack is already created.
+ deferUpdateBounds(HOME_STACK_ID);
+ mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
+ }
+ if (task.stack.mStackId != launchStackId) {
+ moveTaskToStackLocked(
+ taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
+ ANIMATE);
+ }
+ }
+
+ // If the user must confirm credentials (e.g. when first launching a work app and the
+ // Work Challenge is present) let startActivityInPackage handle the intercepting.
+ if (!mService.mUserController.shouldConfirmCredentials(task.userId)
+ && task.getRootActivity() != null) {
+ mService.moveTaskToFrontLocked(task.taskId, 0, bOptions);
+
+ // If we are launching the task in the docked stack, put it into resizing mode so
+ // the window renders full-screen with the background filling the void. Also only
+ // call this at the end to make sure that tasks exists on the window manager side.
+ if (launchStackId == DOCKED_STACK_ID) {
+ setResizingDuringAnimation(taskId);
+ }
+ return ActivityManager.START_TASK_TO_FRONT;
+ }
+ callingUid = task.mCallingUid;
+ callingPackage = task.mCallingPackage;
+ intent = task.intent;
+ intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+ userId = task.userId;
+ int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
+ null, null, 0, 0, bOptions, userId, null, task);
+ if (launchStackId == DOCKED_STACK_ID) {
+ setResizingDuringAnimation(task.taskId);
+ }
+ return result;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index af69c93..e3ca3ea 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -362,7 +362,7 @@
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
- resultRecord, resultStack);
+ resultRecord, resultStack, options);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
@@ -547,12 +547,18 @@
}
if (startedActivityStackId == DOCKED_STACK_ID && prevFocusedStackId == HOME_STACK_ID) {
- // We launch an activity while being in home stack, which means either launcher or
- // recents into docked stack. We don't want the launched activity to be alone in a
- // docked stack, so we want to immediately launch recents too.
- if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
- mWindowManager.showRecentApps();
- return;
+ final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID);
+ final ActivityRecord topActivityHomeStack = homeStack != null
+ ? homeStack.topRunningActivityLocked() : null;
+ if (topActivityHomeStack == null
+ || topActivityHomeStack.mActivityType != RECENTS_ACTIVITY_TYPE) {
+ // We launch an activity while being in home stack, which means either launcher or
+ // recents into docked stack. We don't want the launched activity to be alone in a
+ // docked stack, so we want to immediately launch recents too.
+ if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
+ mWindowManager.showRecentApps();
+ return;
+ }
}
if (startedActivityStackId == PINNED_STACK_ID
@@ -879,6 +885,9 @@
ActivityRecord intentActivity = getReusableIntentActivity();
+ final int preferredLaunchStackId =
+ (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
+
if (intentActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
@@ -938,6 +947,8 @@
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
+ mSupervisor.showNonResizeableDockToastIfNeeded(mStartActivity.task,
+ preferredLaunchStackId, mTargetStack.mStackId);
return START_TASK_TO_FRONT;
}
}
@@ -977,6 +988,8 @@
}
top.deliverNewIntentLocked(
mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ mSupervisor.showNonResizeableDockToastIfNeeded(mStartActivity.task,
+ preferredLaunchStackId, mTargetStack.mStackId);
return START_DELIVERED_TO_TOP;
}
@@ -1063,8 +1076,6 @@
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
- final int preferredLaunchStackId =
- (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
mSupervisor.showNonResizeableDockToastIfNeeded(
mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);
@@ -1297,7 +1308,10 @@
// same component, then instead of launching bring that one to the front.
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
- if (putIntoExistingTask) {
+ if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
+ final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
+ intentActivity = task != null ? task.getTopActivity() : null;
+ } else if (putIntoExistingTask) {
// See if there is a task to bring to the front. If this is a SINGLE_INSTANCE
// activity, there can be one and only one instance of it in the history, and it is
// always in its own unique task, so we do a special search.
@@ -1349,6 +1363,15 @@
intentActivity.task, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
+ } else if ((launchStack.mStackId == DOCKED_STACK_ID
+ || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID)
+ && (mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
+ // If we want to launch adjacent and mTargetStack is not the computed
+ // launch stack - move task to top of computed stack.
+ mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
+ launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
+ ANIMATE);
+ mMovedToFront = true;
}
mOptions = null;
}
@@ -1756,26 +1779,41 @@
if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
return null;
}
+ // Otherwise handle adjacent launch.
// The parent activity doesn't want to launch the activity on top of itself, but
// instead tries to put it onto other side in side-by-side mode.
final ActivityStack parentStack = task != null ? task.stack
: r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack
: mSupervisor.mFocusedStack;
- if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) {
- // If parent was in docked stack, the natural place to launch another activity
- // will be fullscreen, so it can appear alongside the docked window.
- return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+
+ if (parentStack != mSupervisor.mFocusedStack) {
+ // If task's parent stack is not focused - use it during adjacent launch.
+ return parentStack;
} else {
- // If the parent is not in the docked stack, we check if there is docked window
- // and if yes, we will launch into that stack. If not, we just put the new
- // activity into parent's stack, because we can't find a better place.
- final ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
- if (stack != null && stack.getStackVisibilityLocked(r) == STACK_INVISIBLE) {
- // There is a docked stack, but it isn't visible, so we can't launch into that.
- return null;
+ if (mSupervisor.mFocusedStack != null && task == mSupervisor.mFocusedStack.topTask()) {
+ // If task is already on top of focused stack - use it. We don't want to move the
+ // existing focused task to adjacent stack, just deliver new intent in this case.
+ return mSupervisor.mFocusedStack;
+ }
+
+ if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) {
+ // If parent was in docked stack, the natural place to launch another activity
+ // will be fullscreen, so it can appear alongside the docked window.
+ return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED,
+ ON_TOP);
} else {
- return stack;
+ // If the parent is not in the docked stack, we check if there is docked window
+ // and if yes, we will launch into that stack. If not, we just put the new
+ // activity into parent's stack, because we can't find a better place.
+ final ActivityStack dockedStack = mSupervisor.getStack(DOCKED_STACK_ID);
+ if (dockedStack != null
+ && dockedStack.getStackVisibilityLocked(r) == STACK_INVISIBLE) {
+ // There is a docked stack, but it isn't visible, so we can't launch into that.
+ return null;
+ } else {
+ return dockedStack;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b4aa4cf..5407d28 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -558,7 +558,7 @@
}
EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
Process.killProcessQuiet(pid);
- Process.killProcessGroup(info.uid, pid);
+ Process.killProcessGroup(uid, pid);
if (!persistent) {
killed = true;
killedByAm = true;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 4527f1f..715d2d8 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -17,12 +17,12 @@
package com.android.server.display;
import android.content.res.Resources;
-import android.os.Build;
import com.android.server.LocalServices;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import android.content.Context;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -31,7 +31,6 @@
import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.Surface;
@@ -388,7 +387,7 @@
mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
| DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound)
- || (Build.HARDWARE.contains("goldfish")
+ || (Build.IS_EMULATOR
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 49ae293..9b92e4f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2803,7 +2803,7 @@
private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
try {
- mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting uid rules", e);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 2f0532a..c303ceb 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -42,6 +42,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
@@ -54,6 +55,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -102,6 +104,8 @@
private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+ private final Handler mCallbackHandler;
+
public LauncherAppsImpl(Context context) {
mContext = context;
mPm = mContext.getPackageManager();
@@ -109,6 +113,7 @@
mShortcutServiceInternal = Preconditions.checkNotNull(
LocalServices.getService(ShortcutServiceInternal.class));
mShortcutServiceInternal.addListener(mPackageMonitor);
+ mCallbackHandler = BackgroundThread.getHandler();
}
@VisibleForTesting
@@ -165,7 +170,7 @@
* Register a receiver to watch for package broadcasts
*/
private void startWatchingPackageBroadcasts() {
- mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+ mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
}
/**
@@ -550,8 +555,9 @@
}
}
+ @VisibleForTesting
void postToPackageMonitorHandler(Runnable r) {
- mPackageMonitor.getRegisteredHandler().post(r);
+ mCallbackHandler.post(r);
}
private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
diff --git a/services/core/java/com/android/server/policy/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
index da9c001..6b203a9 100644
--- a/services/core/java/com/android/server/policy/EnableAccessibilityController.java
+++ b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
@@ -16,7 +16,9 @@
package com.android.server.policy;
+import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -32,19 +34,25 @@
import android.os.UserManager;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
+import android.util.Log;
import android.util.MathUtils;
import android.view.IWindowManager;
import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerInternal;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import com.android.internal.R;
+import com.android.server.LocalServices;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class EnableAccessibilityController {
+ private static final String TAG = "EnableAccessibilityController";
private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
@@ -75,9 +83,6 @@
}
};
- private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService("window"));
-
private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
.Stub.asInterface(ServiceManager.getService("accessibility"));
@@ -132,7 +137,7 @@
&& !getInstalledSpeakingAccessibilityServices(context).isEmpty();
}
- private static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
+ public static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
Context context) {
List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
services.addAll(AccessibilityManager.getInstance(context)
@@ -213,71 +218,74 @@
}
private void enableAccessibility() {
- List<AccessibilityServiceInfo> services = getInstalledSpeakingAccessibilityServices(
- mContext);
- if (services.isEmpty()) {
+ if (enableAccessibility(mContext)) {
+ mOnAccessibilityEnabledCallback.run();
+ }
+ }
+
+ public static boolean enableAccessibility(Context context) {
+ final IAccessibilityManager accessibilityManager = IAccessibilityManager
+ .Stub.asInterface(ServiceManager.getService("accessibility"));
+ final WindowManagerInternal windowManager = LocalServices.getService(
+ WindowManagerInternal.class);
+ final UserManager userManager = (UserManager) context.getSystemService(
+ Context.USER_SERVICE);
+ ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
+ if (componentName == null) {
+ return false;
+ }
+
+ boolean keyguardLocked = windowManager.isKeyguardLocked();
+ final boolean hasMoreThanOneUser = userManager.getUsers().size() > 1;
+ try {
+ if (!keyguardLocked || !hasMoreThanOneUser) {
+ final int userId = ActivityManager.getCurrentUser();
+ accessibilityManager.enableAccessibilityService(componentName, userId);
+ } else if (keyguardLocked) {
+ accessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
+ componentName, true /* enableTouchExploration */);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot enable accessibilty: " + e);
+ }
+
+ return true;
+ }
+
+ public static void disableAccessibility(Context context) {
+ final IAccessibilityManager accessibilityManager = IAccessibilityManager
+ .Stub.asInterface(ServiceManager.getService("accessibility"));
+ ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
+ if (componentName == null) {
return;
}
- boolean keyguardLocked = false;
+
+ final int userId = ActivityManager.getCurrentUser();
try {
- keyguardLocked = mWindowManager.isKeyguardLocked();
- } catch (RemoteException re) {
- /* ignore */
+ accessibilityManager.disableAccessibilityService(componentName, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot disable accessibility " + e);
+ }
+ }
+
+ public static boolean isAccessibilityEnabled(Context context) {
+ final AccessibilityManager accessibilityManager =
+ context.getSystemService(AccessibilityManager.class);
+ List enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN);
+ return enabledServices != null && !enabledServices.isEmpty();
+ }
+
+ @Nullable
+ public static ComponentName getInstalledSpeakingAccessibilityServiceComponent(
+ Context context) {
+ List<AccessibilityServiceInfo> services =
+ getInstalledSpeakingAccessibilityServices(context);
+ if (services.isEmpty()) {
+ return null;
}
- final boolean hasMoreThanOneUser = mUserManager.getUsers().size() > 1;
-
- AccessibilityServiceInfo service = services.get(0);
- boolean enableTouchExploration = (service.flags
- & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
- // Try to find a service supporting explore by touch.
- if (!enableTouchExploration) {
- final int serviceCount = services.size();
- for (int i = 1; i < serviceCount; i++) {
- AccessibilityServiceInfo candidate = services.get(i);
- if ((candidate.flags & AccessibilityServiceInfo
- .FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0) {
- enableTouchExploration = true;
- service = candidate;
- break;
- }
- }
- }
-
- ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
- ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
- if (!keyguardLocked || !hasMoreThanOneUser) {
- final int userId = ActivityManager.getCurrentUser();
- String enabledServiceString = componentName.flattenToString();
- ContentResolver resolver = mContext.getContentResolver();
- // Enable one speaking accessibility service.
- Settings.Secure.putStringForUser(resolver,
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enabledServiceString, userId);
- // Allow the services we just enabled to toggle touch exploration.
- Settings.Secure.putStringForUser(resolver,
- Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
- enabledServiceString, userId);
- // Enable touch exploration.
- if (enableTouchExploration) {
- Settings.Secure.putIntForUser(resolver, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
- 1, userId);
- }
- // Enable accessibility script injection (AndroidVox) for web content.
- Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- 1, userId);
- // Turn on accessibility mode last.
- Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_ENABLED,
- 1, userId);
- } else if (keyguardLocked) {
- try {
- mAccessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
- componentName, enableTouchExploration);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
-
- mOnAccessibilityEnabledCallback.run();
+ ServiceInfo serviceInfo = services.get(0).getResolveInfo().serviceInfo;
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d92d942..1645366 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2778,8 +2778,10 @@
// If the divider is behind the navigation bar, don't animate.
if (mNavigationBar != null
- && (win.getFrameLw().top + insets >= mNavigationBar.getFrameLw().top
- || win.getFrameLw().left + insets >= mNavigationBar.getFrameLw().left)) {
+ && ((mNavigationBarOnBottom
+ && win.getFrameLw().top + insets >= mNavigationBar.getFrameLw().top)
+ || (!mNavigationBarOnBottom
+ && win.getFrameLw().left + insets >= mNavigationBar.getFrameLw().left))) {
return 0;
}
if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
index 9d353c6..86d0468 100644
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -29,6 +29,8 @@
import android.view.animation.TranslateAnimation;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
import static android.view.WindowManagerInternal.*;
@@ -103,6 +105,20 @@
}
});
}
+
+ @Override
+ public void onAppTransitionFinishedLocked(IBinder token) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ StatusBarManagerInternal statusbar = LocalServices.getService(
+ StatusBarManagerInternal.class);
+ if (statusbar != null) {
+ statusbar.appTransitionFinished();
+ }
+ }
+ });
+ }
};
public StatusBarController() {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 6bda4ed..9614417 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -34,4 +34,5 @@
void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
Rect fullscreenBounds, Rect dockedBounds, String cause);
void toggleSplitScreen();
+ void appTransitionFinished();
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 403a4c6..4a00ebd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -214,6 +214,15 @@
} catch (RemoteException ex) {}
}
}
+
+ public void appTransitionFinished() {
+ enforceStatusBarService();
+ if (mBar != null) {
+ try {
+ mBar.appTransitionFinished();
+ } catch (RemoteException ex) {}
+ }
+ }
};
// ================================================================================
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index fb9b1ce..4848523 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1262,6 +1262,7 @@
return null;
}
+ @Override
public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
if (isWallpaperSupported(callingPackage) && isWallpaperSettingAllowed(callingPackage)) {
setWallpaperComponent(name);
@@ -1269,6 +1270,7 @@
}
// ToDo: Remove this version of the function
+ @Override
public void setWallpaperComponent(ComponentName name) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
@@ -1281,7 +1283,9 @@
final long ident = Binder.clearCallingIdentity();
try {
wallpaper.imageWallpaperPending = false;
- bindWallpaperComponentLocked(name, false, true, wallpaper, null);
+ if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+ wallpaper.wallpaperId = makeWallpaperIdLocked();
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2a57d8e..d684278 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -50,6 +50,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Path;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
@@ -76,6 +77,7 @@
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.animation.ClipRectLRAnimation;
import com.android.server.wm.animation.ClipRectTBAnimation;
+import com.android.server.wm.animation.CurvedTranslateAnimation;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -130,6 +132,8 @@
public static final int TRANSIT_TASK_IN_PLACE = 17;
/** An activity is being relaunched (e.g. due to configuration change). */
public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
+ /** A task is being docked from recents. */
+ public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
/** Fraction of animation at which the recents thumbnail stays completely transparent */
private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
@@ -142,13 +146,15 @@
static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+ private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
+ new PathInterpolator(0.85f, 0f, 1f, 1f);
+
/**
* Maximum duration for the clip reveal animation. This is used when there is a lot of movement
* involved, to make it more understandable.
*/
private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
- private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
private final Context mContext;
@@ -209,6 +215,7 @@
private final Interpolator mThumbnailFadeOutInterpolator;
private final Interpolator mLinearOutSlowInInterpolator;
private final Interpolator mFastOutLinearInInterpolator;
+ private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
private final int mClipRevealTranslationY;
@@ -229,6 +236,8 @@
com.android.internal.R.interpolator.linear_out_slow_in);
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_linear_in);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -815,12 +824,14 @@
* Prepares the specified animation with a standard duration, interpolator, etc.
*/
Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
- int duration, Interpolator interpolator) {
+ long duration, Interpolator interpolator) {
if (duration > 0) {
a.setDuration(duration);
}
a.setFillAfter(true);
- a.setInterpolator(interpolator);
+ if (interpolator != null) {
+ a.setInterpolator(interpolator);
+ }
a.initialize(appWidth, appHeight, appWidth, appHeight);
return a;
}
@@ -869,55 +880,95 @@
* This animation runs for the thumbnail that gets cross faded with the enter/exit activity
* when a thumbnail is specified with the pending animation override.
*/
- Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, Bitmap thumbnailHeader,
- final int taskId) {
+ Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
+ Bitmap thumbnailHeader, final int taskId, int orientation) {
Animation a;
final int thumbWidthI = thumbnailHeader.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = thumbnailHeader.getHeight();
- final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
final int appWidth = appRect.width();
float scaleW = appWidth / thumbWidth;
- float unscaledHeight = thumbHeight * scaleW;
getNextAppTransitionStartRect(taskId, mTmpRect);
- final float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
- final float toY = appRect.top + -unscaledStartY;
+ final float fromX;
+ final float fromY;
+ final float toX;
+ final float toY;
+ final float pivotX;
+ final float pivotY;
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ fromX = mTmpRect.left;
+ fromY = mTmpRect.top;
+
+ // For the curved translate animation to work, the pivot points needs to be at the
+ // same absolute position as the one from the real surface.
+ toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
+ toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
+ pivotX = mTmpRect.width() / 2;
+ pivotY = appRect.height() / 2 / scaleW;
+ } else {
+ pivotX = 0;
+ pivotY = 0;
+ fromX = mTmpRect.left;
+ fromY = mTmpRect.top;
+ toX = appRect.left;
+ toY = appRect.top;
+ }
+ final long duration = getAspectScaleDuration();
+ final Interpolator interpolator = getAspectScaleInterpolator();
if (mNextAppTransitionScaleUp) {
// Animation up from the thumbnail to the full screen
- Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
- mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
- scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
- scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+ Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
+ scale.setInterpolator(interpolator);
+ scale.setDuration(duration);
Animation alpha = new AlphaAnimation(1f, 0f);
- alpha.setInterpolator(mThumbnailFadeOutInterpolator);
- alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
- final float toX = appRect.left + appRect.width() / 2 -
- (mTmpRect.left + thumbWidth / 2);
- Animation translate = new TranslateAnimation(0, toX, 0, toY);
- translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
- translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+ alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+ ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
+ alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+ ? duration / 2
+ : duration);
+ Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
+ translate.setInterpolator(interpolator);
+ translate.setDuration(duration);
+
+ mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
+ mTmpToClipRect.set(appRect);
+
+ // Containing frame is in screen space, but we need the clip rect in the
+ // app space.
+ mTmpToClipRect.offsetTo(0, 0);
+ mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
+ mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
+
+ if (contentInsets != null) {
+ mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
+ (int) (-contentInsets.top * scaleW),
+ (int) (-contentInsets.right * scaleW),
+ (int) (-contentInsets.bottom * scaleW));
+ }
+
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ clipAnim.setInterpolator(interpolator);
+ clipAnim.setDuration(duration);
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
set.addAnimation(scale);
set.addAnimation(alpha);
set.addAnimation(translate);
+ set.addAnimation(clipAnim);
a = set;
} else {
// Animation down from the full screen to the thumbnail
- Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
- mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
- scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
- scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+ Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
+ scale.setInterpolator(interpolator);
+ scale.setDuration(duration);
Animation alpha = new AlphaAnimation(0f, 1f);
alpha.setInterpolator(mThumbnailFadeInInterpolator);
- alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
- final float toX = appRect.left + appRect.width() / 2 -
- (mTmpRect.left + thumbWidth / 2);
- Animation translate = new TranslateAnimation(toX, 0, toY, 0);
- translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
- translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
+ alpha.setDuration(duration);
+ Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
+ translate.setInterpolator(interpolator);
+ translate.setDuration(duration);
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
@@ -928,7 +979,48 @@
}
return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
- TOUCH_RESPONSE_INTERPOLATOR);
+ null);
+ }
+
+ private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
+
+ // Almost no x-change - use linear animation
+ if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ return new TranslateAnimation(fromX, toX, fromY, toY);
+ } else {
+ final Path path = createCurvedPath(fromX, toX, fromY, toY);
+ return new CurvedTranslateAnimation(path);
+ }
+ }
+
+ private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
+ final Path path = new Path();
+ path.moveTo(fromX, fromY);
+
+ if (fromY > toY) {
+ // If the object needs to go up, move it in horizontal direction first, then vertical.
+ path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
+ } else {
+ // If the object needs to go down, move it in vertical direction first, then horizontal.
+ path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
+ }
+ return path;
+ }
+
+ private long getAspectScaleDuration() {
+ if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
+ } else {
+ return THUMBNAIL_APP_TRANSITION_DURATION;
+ }
+ }
+
+ private Interpolator getAspectScaleInterpolator() {
+ if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ return mFastOutSlowInInterpolator;
+ } else {
+ return TOUCH_RESPONSE_INTERPOLATOR;
+ }
}
/**
@@ -949,15 +1041,16 @@
final int thumbStartX = mTmpRect.left - containingFrame.left;
final int thumbStartY = mTmpRect.top - containingFrame.top;
- // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
- float scale = 1f;
- int scaledTopDecor = 0;
-
switch (thumbTransitState) {
- case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
- if (freeform) {
+ case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
+ case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
+ final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
+ if (freeform && scaleUp) {
a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
containingFrame, surfaceInsets, taskId);
+ } else if (freeform) {
+ a = createAspectScaledThumbnailExitFreeformAnimationLocked(
+ containingFrame, surfaceInsets, taskId);
} else {
AnimationSet set = new AnimationSet(true);
@@ -976,16 +1069,33 @@
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
// We scale the width and clip to the top/left square
- scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
- scaledTopDecor = (int) (scale * contentInsets.top);
+ // We scale the width and clip to the top/left square
+ float scale = thumbWidth /
+ (appWidth - contentInsets.left - contentInsets.right);
int unscaledThumbHeight = (int) (thumbHeight / scale);
mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
- Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
- computePivot(mTmpRect.left - containingFrame.left, scale),
- computePivot(mTmpRect.top - containingFrame.top, scale));
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+ mNextAppTransitionInsets.set(contentInsets);
+
+ Animation scaleAnim = new ScaleAnimation(
+ scaleUp ? scale : 1, scaleUp ? 1 : scale,
+ scaleUp ? scale : 1, scaleUp ? 1 : scale,
+ containingFrame.width() / 2f,
+ containingFrame.height() / 2f + contentInsets.top);
+ final float targetX = (mTmpRect.left - containingFrame.left);
+ final float x = containingFrame.width() / 2f
+ - containingFrame.width() / 2f * scale;
+ final float targetY = (mTmpRect.top - containingFrame.top);
+ final float y = containingFrame.height() / 2f
+ - containingFrame.height() / 2f * scale;
+ final float startX = targetX - x;
+ final float startY = targetY - y;
+ Animation clipAnim = scaleUp
+ ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
+ : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
+ Animation translateAnim = scaleUp
+ ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
+ : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
set.addAnimation(clipAnim);
set.addAnimation(scaleAnim);
@@ -996,14 +1106,18 @@
mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(thumbStartX, 0,
- thumbStartY - contentInsets.top, 0);
+ Animation clipAnim = scaleUp
+ ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
+ : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
+ Animation translateAnim = scaleUp
+ ? createCurvedMotion(thumbStartX, 0,
+ thumbStartY - contentInsets.top, 0)
+ : createCurvedMotion(0, thumbStartX, 0,
+ thumbStartY - contentInsets.top);
set.addAnimation(clipAnim);
set.addAnimation(translateAnim);
}
-
a = set;
a.setZAdjustment(Animation.ZORDER_TOP);
}
@@ -1031,68 +1145,12 @@
}
break;
}
- case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
- // App window scaling down from full screen
- if (freeform) {
- a = createAspectScaledThumbnailExitFreeformAnimationLocked(
- containingFrame, surfaceInsets, taskId);
- } else {
- AnimationSet set = new AnimationSet(true);
- mTmpFromClipRect.set(containingFrame);
- mTmpToClipRect.set(containingFrame);
-
- // Containing frame is in screen space, but we need the clip rect in the
- // app space.
- mTmpFromClipRect.offsetTo(0, 0);
- mTmpToClipRect.offsetTo(0, 0);
-
- // Exclude insets region from the target clip.
- mTmpToClipRect.inset(contentInsets);
- mNextAppTransitionInsets.set(contentInsets);
-
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- // We scale the width and clip to the top/left square
- scale = thumbWidth / (appWidth - contentInsets.left - contentInsets.right);
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbHeight = (int) (thumbHeight / scale);
- mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
-
- Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
- computePivot(mTmpRect.left - containingFrame.left, scale),
- computePivot(mTmpRect.top - containingFrame.top, scale));
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
-
- set.addAnimation(clipAnim);
- set.addAnimation(scaleAnim);
- set.addAnimation(translateAnim);
-
- } else {
- // In landscape, we don't scale at all and only crop
- mTmpToClipRect.bottom = mTmpToClipRect.top + thumbHeightI;
- mTmpToClipRect.right = mTmpToClipRect.left + thumbWidthI;
-
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, thumbStartX, 0,
- thumbStartY - contentInsets.top);
-
- set.addAnimation(clipAnim);
- set.addAnimation(translateAnim);
- }
-
- a = set;
- a.setZAdjustment(Animation.ZORDER_TOP);
- }
- break;
- }
default:
throw new RuntimeException("Invalid thumbnail transition state");
}
- int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
- THUMBNAIL_APP_TRANSITION_DURATION);
- return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
- TOUCH_RESPONSE_INTERPOLATOR);
+ return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
+ getAspectScaleDuration(), getAspectScaleInterpolator());
}
private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
@@ -1446,6 +1504,7 @@
? WindowAnimation_activityCloseEnterAnimation
: WindowAnimation_activityCloseExitAnimation;
break;
+ case TRANSIT_DOCK_TASK_FROM_RECENTS:
case TRANSIT_TASK_OPEN:
animAttr = enter
? WindowAnimation_taskOpenEnterAnimation
@@ -1504,6 +1563,8 @@
int getAppStackClipMode() {
return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
+ || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
+ || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
? STACK_CLIP_NONE
: STACK_CLIP_AFTER_ANIM;
}
@@ -1727,6 +1788,9 @@
case TRANSIT_ACTIVITY_RELAUNCH: {
return "TRANSIT_ACTIVITY_RELAUNCH";
}
+ case TRANSIT_DOCK_TASK_FROM_RECENTS: {
+ return "TRANSIT_DOCK_TASK_FROM_RECENTS";
+ }
default: {
return "<UNKNOWN>";
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 6225fc6..aae52e8 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -77,8 +77,6 @@
// requires that the duration of the two animations are the same.
SurfaceControl thumbnail;
int thumbnailTransactionSeq;
- int thumbnailX;
- int thumbnailY;
int thumbnailLayer;
int thumbnailForceAboveLayer;
Animation thumbnailAnimation;
@@ -254,7 +252,6 @@
thumbnailTransformation.clear();
final long animationFrameTime = getAnimationFrameTime(thumbnailAnimation, currentTime);
thumbnailAnimation.getTransformation(animationFrameTime, thumbnailTransformation);
- thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
@@ -288,6 +285,7 @@
}
thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
+ thumbnail.setWindowCrop(thumbnailTransformation.getClipRect());
}
/**
@@ -461,8 +459,6 @@
}
if (thumbnail != null) {
pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
- pw.print(" x="); pw.print(thumbnailX);
- pw.print(" y="); pw.print(thumbnailY);
pw.print(" layer="); pw.println(thumbnailLayer);
pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
pw.print(prefix); pw.print("thumbnailTransformation=");
diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java
new file mode 100644
index 0000000..08acf9d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DragResizeMode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+
+/**
+ * Describes the mode in which a window is drag resizing.
+ */
+class DragResizeMode {
+
+ /**
+ * Freeform mode: Client surface is fullscreen, and client is responsible to draw window at
+ * the correct position.
+ */
+ static final int DRAG_RESIZE_MODE_FREEFORM = 0;
+
+ /**
+ * Mode for resizing the docked (and adjacent) stack: Client surface is fullscreen, but window
+ * is drawn at (0, 0), window manager is responsible for positioning the surface when draging.
+ */
+ static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
+
+ static boolean isModeAllowedForStack(int stackId, int mode) {
+ switch (mode) {
+ case DRAG_RESIZE_MODE_FREEFORM:
+ return stackId == FREEFORM_WORKSPACE_STACK_ID;
+ case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
+ return stackId == DOCKED_STACK_ID
+ || stackId == FULLSCREEN_WORKSPACE_STACK_ID
+ || stackId == HOME_STACK_ID;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f097eb2..4e8f19e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -18,8 +18,6 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -103,6 +101,7 @@
// Whether the task is currently being drag-resized
private boolean mDragResizing;
+ private int mDragResizeMode;
private boolean mHomeTask;
@@ -140,41 +139,7 @@
final String text =
mService.mContext.getString(R.string.dock_non_resizeble_failed_to_dock_text);
mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST, 0, 0, text).sendToTarget();
- return;
}
-
- final int dockSide = mStack.getDockSide();
- if (mResizeMode != RESIZE_MODE_FORCE_RESIZEABLE || dockSide == DOCKED_INVALID) {
- return;
- }
-
- int xOffset = 0;
- int yOffset = 0;
- mStack.getBounds(mTmpRect);
-
- if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
- // The toast was originally placed at the bottom and centered. To place it at the
- // bottom-center of the stack, we offset it horizontally by the diff between the center
- // of the stack bounds vs. the center of the screen.
- displayContent.getLogicalDisplayRect(mTmpRect2);
- xOffset = mTmpRect.centerX() - mTmpRect2.centerX();
- } else if (dockSide == DOCKED_TOP) {
- // The toast was originally placed at the bottom and centered. To place it at the bottom
- // center of the top stack, we offset it vertically by the diff between the bottom of
- // the stack bounds vs. the bottom of the content rect.
- //
- // Note here we use the content rect instead of the display rect, as we want the toast's
- // distance to the dock divider (when it's placed at the top half) to be the same as
- // it's distance to the top of the navigation bar (when it's placed at the bottom).
-
- // We don't adjust for DOCKED_BOTTOM case since it's already at the bottom.
- displayContent.getContentRect(mTmpRect2);
- yOffset = mTmpRect2.bottom - mTmpRect.bottom;
- }
- final String text =
- mService.mContext.getString(R.string.dock_forced_resizable);
- mService.mH.obtainMessage(SHOW_NON_RESIZEABLE_DOCK_TOAST,
- xOffset, yOffset, text).sendToTarget();
}
void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
@@ -543,9 +508,14 @@
mStack.getDisplayContent().getLogicalDisplayRect(out);
}
- void setDragResizing(boolean dragResizing) {
+ void setDragResizing(boolean dragResizing, int dragResizeMode) {
if (mDragResizing != dragResizing) {
+ if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
+ throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
+ + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
+ }
mDragResizing = dragResizing;
+ mDragResizeMode = dragResizeMode;
resetDragResizingChangeReported();
}
}
@@ -564,6 +534,10 @@
return mDragResizing || (mStack != null && mStack.isDragResizing());
}
+ int getDragResizeMode() {
+ return mDragResizeMode;
+ }
+
void updateDisplayInfo(final DisplayContent displayContent) {
if (displayContent == null) {
return;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 92701de..ae70aa8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -29,6 +29,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.dipToPixel;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
@@ -379,7 +380,7 @@
private void endDragLocked() {
mResizing = false;
- mTask.setDragResizing(false);
+ mTask.setDragResizing(false, DRAG_RESIZE_MODE_FREEFORM);
}
/** Returns true if the move operation should be ended. */
@@ -409,7 +410,7 @@
bottom = Math.max(top + mMinVisibleHeight, bottom + deltaY);
}
mWindowDragBounds.set(left, top, right, bottom);
- mTask.setDragResizing(true);
+ mTask.setDragResizing(true, DRAG_RESIZE_MODE_FREEFORM);
return false;
}
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index e018a4e..f76f03f 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -227,6 +227,10 @@
w.mLayer = layer;
w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
getSpecialWindowAnimLayerAdjustment(w);
+ if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0
+ && w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
+ w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
+ }
}
void dump(PrintWriter pw, String s) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 708ddff..5771d69 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -202,6 +202,8 @@
import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -799,7 +801,13 @@
= new WindowManagerInternal.AppTransitionListener() {
@Override
+ public void onAppTransitionCancelledLocked() {
+ mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_CANCELLED);
+ }
+
+ @Override
public void onAppTransitionFinishedLocked(IBinder token) {
+ mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_FINISHED);
AppWindowToken atoken = findAppWindowToken(token);
if (atoken == null) {
return;
@@ -2921,9 +2929,9 @@
}
}
final boolean freeformResizing = win.isDragResizing()
- && win.getResizeMode() == WindowState.DRAG_RESIZE_MODE_FREEFORM;
+ && win.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
final boolean dockedResizing = win.isDragResizing()
- && win.getResizeMode() == WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+ && win.getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
result |= freeformResizing ? WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM : 0;
result |= dockedResizing ? WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED : 0;
if (win.isAnimatingWithSavedSurface()) {
@@ -4025,8 +4033,6 @@
wAppAnimator.thumbnail.destroy();
}
wAppAnimator.thumbnail = tAppAnimator.thumbnail;
- wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
- wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
tAppAnimator.thumbnail = null;
@@ -4990,6 +4996,23 @@
}
}
+ /**
+ * Puts a specific task into docked drag resizing mode. See {@link DragResizeMode}.
+ *
+ * @param taskId The id of the task to put into drag resize mode.
+ * @param resizing Whether to put the task into drag resize mode.
+ */
+ public void setTaskDockedResizing(int taskId, boolean resizing) {
+ synchronized (mWindowMap) {
+ Task task = mTaskIdToTask.get(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("setTaskDockedResizing: taskId " + taskId
+ + " not found.");
+ }
+ task.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+ }
+ }
+
public void scrollTask(int taskId, Rect bounds) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
@@ -5736,7 +5759,7 @@
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_windowEnableCircularEmulatorDisplayOverlay)
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false)
- && Build.HARDWARE.contains("goldfish")) {
+ && Build.IS_EMULATOR) {
mH.sendMessage(mH.obtainMessage(H.SHOW_EMULATOR_DISPLAY_OVERLAY));
}
}
@@ -7695,7 +7718,9 @@
public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
- public static final int NOTIFY_STARTING_WINDOW_DRAWN = 48;
+ public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
+ public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
+ public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
/**
* Used to denote that an integer field in a message will not be used.
@@ -8276,6 +8301,14 @@
mAmInternal.notifyAppTransitionStarting(msg.arg1);
}
break;
+ case NOTIFY_APP_TRANSITION_CANCELLED: {
+ mAmInternal.notifyAppTransitionCancelled();
+ }
+ break;
+ case NOTIFY_APP_TRANSITION_FINISHED: {
+ mAmInternal.notifyAppTransitionFinished();
+ }
+ break;
case NOTIFY_STARTING_WINDOW_DRAWN: {
mAmInternal.notifyStartingWindowDrawn();
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 38fda1b..a302006 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -88,6 +88,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -124,9 +126,6 @@
// to capture touch events in that area.
static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
- static final int DRAG_RESIZE_MODE_FREEFORM = 0;
- static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
-
static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
final WindowManagerService mService;
@@ -756,20 +755,10 @@
mVisibleFrame.set(mContentFrame);
mStableFrame.set(mContentFrame);
} else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
- if (isVisibleLw() || mWinAnimator.isAnimating()) {
- // We don't adjust the dock divider frame for reasons other than performance. The
- // real reason is that if it gets adjusted before it is shown for the first time,
- // it would get size (0, 0). This causes a problem when we finally show the dock
- // divider and try to draw to it. We do set the surface size at that moment to
- // the correct size, but it's too late for the Surface Flinger to make it
- // available for view rendering and as a result the renderer receives size 1, 1.
- // This way we just keep the divider at the original size and Surface Flinger
- // will return the correct value to the renderer.
- mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
- mContentFrame.set(mFrame);
- if (!mFrame.equals(mLastFrame)) {
- mMovedByResize = true;
- }
+ mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
+ mContentFrame.set(mFrame);
+ if (!mFrame.equals(mLastFrame)) {
+ mMovedByResize = true;
}
} else {
mContentFrame.set(Math.max(mContentFrame.left, frame.left),
@@ -1309,7 +1298,7 @@
*/
boolean hasMoved() {
return mHasSurface && (mContentChanged || mMovedByResize)
- && !mAnimatingExit && !mWinAnimator.mLastHidden && mService.okToDisplay()
+ && !mAnimatingExit && mService.okToDisplay()
&& (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
&& (mAttachedWindow == null || !mAttachedWindow.hasMoved());
}
@@ -2258,7 +2247,7 @@
return mResizeMode;
}
- private boolean computeDragResizing() {
+ boolean computeDragResizing() {
final Task task = getTask();
if (task == null) {
return false;
@@ -2288,9 +2277,14 @@
return;
}
mDragResizing = resizing;
- mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
- ? DRAG_RESIZE_MODE_DOCKED_DIVIDER
- : DRAG_RESIZE_MODE_FREEFORM;
+ final Task task = getTask();
+ if (task != null && task.isDragResizing()) {
+ mResizeMode = task.getDragResizeMode();
+ } else {
+ mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
+ ? DRAG_RESIZE_MODE_DOCKED_DIVIDER
+ : DRAG_RESIZE_MODE_FREEFORM;
+ }
}
boolean isDragResizing() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 83b6104..1e103f0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -20,6 +20,8 @@
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
@@ -38,8 +40,6 @@
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 909c5f2..3b0081d 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -19,6 +19,7 @@
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -31,13 +32,21 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerService.H.*;
-import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
-import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.DO_TRAVERSAL;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
+import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
+import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
+import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
@@ -688,7 +697,8 @@
w.getTask().mStack.isAdjustedForMinimizedDockedStack();
if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !w.isDragResizing() && !adjustedForMinimizedDockedStack
- && (task == null || !w.getTask().mStack.getFreezeMovementAnimations())) {
+ && (task == null || !w.getTask().mStack.getFreezeMovementAnimations())
+ && !w.mWinAnimator.mLastHidden) {
winAnimator.setMoveAnimation(left, top);
} else if (w.mAttrs.type == TYPE_DOCK_DIVIDER &&
displayContent.getDockedDividerController().isAdjustingForIme()) {
@@ -705,11 +715,11 @@
w.mClient.moved(left, top);
} catch (RemoteException e) {
}
+ w.mMovedByResize = false;
}
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
w.mContentChanged = false;
- w.mMovedByResize = false;
// Moved from updateWindowsAndWallpaperLocked().
if (w.mHasSurface) {
@@ -1224,6 +1234,10 @@
if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
}
+ if (mService.mAppTransition.getAppTransition()
+ == AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START);
+ }
}
return topOpeningApp;
}
@@ -1562,12 +1576,13 @@
WindowState win = appToken.findMainWindow();
Rect appRect = win != null ? win.getContentFrameLw() :
new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+ Rect insets = win != null ? win.mContentInsets : null;
// For the new aspect-scaled transition, we want it to always show
// above the animating opening/closing window, and we want to
// synchronize its thumbnail surface with the surface for the
// open/close animation (only on the way down)
anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
- thumbnailHeader, taskId);
+ insets, thumbnailHeader, taskId, mService.mCurConfiguration.orientation);
openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
openingAppAnimator.deferThumbnailDestruction =
!mService.mAppTransition.isNextThumbnailTransitionScaleUp();
@@ -1582,8 +1597,6 @@
openingAppAnimator.thumbnailLayer = openingLayer;
openingAppAnimator.thumbnailAnimation = anim;
mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
- openingAppAnimator.thumbnailX = mTmpStartRect.left;
- openingAppAnimator.thumbnailY = mTmpStartRect.top;
} catch (Surface.OutOfResourcesException e) {
Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w="
+ dirty.width() + " h=" + dirty.height(), e);
diff --git a/services/core/java/com/android/server/wm/animation/CurvedTranslateAnimation.java b/services/core/java/com/android/server/wm/animation/CurvedTranslateAnimation.java
new file mode 100644
index 0000000..33ac2ff
--- /dev/null
+++ b/services/core/java/com/android/server/wm/animation/CurvedTranslateAnimation.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm.animation;
+
+import android.animation.KeyframeSet;
+import android.animation.PathKeyframes;
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+/**
+ * Translate animation which follows a curved path.
+ */
+public class CurvedTranslateAnimation extends Animation {
+
+ private final PathKeyframes mKeyframes;
+
+ public CurvedTranslateAnimation(Path path) {
+ mKeyframes = KeyframeSet.ofPath(path);
+ }
+
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ PointF location = (PointF) mKeyframes.getValue(interpolatedTime);
+ t.getMatrix().setTranslate(location.x, location.y);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 72a458b..622e46e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -313,7 +313,7 @@
public void testScreenChangesRules() throws Exception {
Future<Void> future;
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -322,7 +322,7 @@
verifyAndReset();
// push strict policy for foreground uid, verify ALLOW rule
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -332,7 +332,7 @@
// now turn screen off and verify REJECT rule
expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
- expectSetUidNetworkRules(UID_A, true);
+ expectSetUidMeteredNetworkBlacklist(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
@@ -342,7 +342,7 @@
// and turn screen back on, verify ALLOW rule restored
expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -354,7 +354,7 @@
public void testPolicyNone() throws Exception {
Future<Void> future;
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -363,7 +363,7 @@
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in foreground
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -372,7 +372,7 @@
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in background
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -385,7 +385,7 @@
Future<Void> future;
// POLICY_REJECT should RULE_ALLOW in background
- expectSetUidNetworkRules(UID_A, true);
+ expectSetUidMeteredNetworkBlacklist(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
@@ -394,7 +394,7 @@
verifyAndReset();
// POLICY_REJECT should RULE_ALLOW in foreground
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, true);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -403,7 +403,7 @@
verifyAndReset();
// POLICY_REJECT should RULE_REJECT in background
- expectSetUidNetworkRules(UID_A, true);
+ expectSetUidMeteredNetworkBlacklist(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
@@ -416,7 +416,7 @@
Future<Void> future;
// POLICY_NONE should have RULE_ALLOW in background
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -426,7 +426,7 @@
verifyAndReset();
// adding POLICY_REJECT should cause RULE_REJECT
- expectSetUidNetworkRules(UID_A, true);
+ expectSetUidMeteredNetworkBlacklist(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
@@ -435,7 +435,7 @@
verifyAndReset();
// removing POLICY_REJECT should return us to RULE_ALLOW
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -632,7 +632,7 @@
Future<Void> future;
// POLICY_REJECT should RULE_REJECT in background
- expectSetUidNetworkRules(UID_A, true);
+ expectSetUidMeteredNetworkBlacklist(UID_A, true);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
@@ -641,7 +641,7 @@
verifyAndReset();
// uninstall should clear RULE_REJECT
- expectSetUidNetworkRules(UID_A, false);
+ expectSetUidMeteredNetworkBlacklist(UID_A, false);
expectSetUidForeground(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
@@ -890,9 +890,9 @@
expectLastCall().atLeastOnce();
}
- private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
+ private void expectSetUidMeteredNetworkBlacklist(int uid, boolean rejectOnQuotaInterfaces)
throws Exception {
- mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces);
expectLastCall().atLeastOnce();
}
diff --git a/tools/layoutlib/.idea/codeStyleSettings.xml b/tools/layoutlib/.idea/codeStyleSettings.xml
index 89f7b34..ac90d1e 100644
--- a/tools/layoutlib/.idea/codeStyleSettings.xml
+++ b/tools/layoutlib/.idea/codeStyleSettings.xml
@@ -40,6 +40,7 @@
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA">
+ <option name="KEEP_LINE_BREAKS" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
@@ -55,6 +56,7 @@
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
+ <option name="WRAP_LONG_LINES" value="true" />
<arrangement>
<groups>
<group>
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
index 6c775b9..ea320c7 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -647,15 +647,15 @@
static String getResourceName(Resources resources, int resid) throws NotFoundException {
boolean[] platformOut = new boolean[1];
Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
- String namespace;
+ String packageName;
if (resourceInfo != null) {
if (platformOut[0]) {
- namespace = SdkConstants.ANDROID_NS_NAME;
+ packageName = SdkConstants.ANDROID_NS_NAME;
} else {
- namespace = resources.mContext.getPackageName();
- namespace = namespace == null ? SdkConstants.APP_PREFIX : namespace;
+ packageName = resources.mContext.getPackageName();
+ packageName = packageName == null ? SdkConstants.APP_PREFIX : packageName;
}
- return namespace + ':' + resourceInfo.getFirst().getName() + '/' +
+ return packageName + ':' + resourceInfo.getFirst().getName() + '/' +
resourceInfo.getSecond();
}
throwException(resid, null);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 4e4fcd0..0c53753 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -122,7 +122,7 @@
// build the context
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
- mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(),
+ mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(mParams),
mParams.getTargetSdkVersion(), mParams.isRtlSupported());
setUp();
@@ -130,7 +130,6 @@
return SUCCESS.createResult();
}
-
/**
* Prepares the scene for action.
* <p>
@@ -320,10 +319,11 @@
}
}
- private Configuration getConfiguration() {
+ // VisibleForTesting
+ public static Configuration getConfiguration(RenderParams params) {
Configuration config = new Configuration();
- HardwareConfig hardwareConfig = mParams.getHardwareConfig();
+ HardwareConfig hardwareConfig = params.getHardwareConfig();
ScreenSize screenSize = hardwareConfig.getScreenSize();
if (screenSize != null) {
@@ -392,7 +392,7 @@
} else {
config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_UNDEFINED;
}
- String locale = getParams().getLocale();
+ String locale = params.getLocale();
if (locale != null && !locale.isEmpty()) config.locale = new Locale(locale);
// TODO: fill in more config info.
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index c2f06e8..a5561fa 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -29,11 +29,14 @@
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.io.FolderWrapper;
import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
import com.android.resources.Density;
import com.android.resources.Navigation;
+import com.android.resources.ResourceType;
import com.android.utils.ILogger;
import org.junit.AfterClass;
@@ -42,13 +45,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
import java.io.File;
-import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
@@ -160,13 +165,8 @@
if (!host.isDirectory()) {
return null;
}
- File[] hosts = host.listFiles(new FileFilter() {
- @Override
- public boolean accept(File path) {
- return path.isDirectory() && (path.getName().startsWith("linux-") || path.getName()
- .startsWith("darwin-"));
- }
- });
+ File[] hosts = host.listFiles(path -> path.isDirectory() &&
+ (path.getName().startsWith("linux-") || path.getName().startsWith("darwin-")));
for (File hostOut : hosts) {
String platformDir = getPlatformDirFromHostOut(hostOut);
if (platformDir != null) {
@@ -184,12 +184,9 @@
if (!sdkDir.isDirectory()) {
return null;
}
- File[] sdkDirs = sdkDir.listFiles(new FileFilter() {
- @Override
- public boolean accept(File path) {
- // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7)
- return path.isDirectory() && path.getName().startsWith("sdk");
- }
+ File[] sdkDirs = sdkDir.listFiles(path -> {
+ // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7)
+ return path.isDirectory() && path.getName().startsWith("sdk");
});
for (File dir : sdkDirs) {
String platformDir = getPlatformDirFromHostOutSdkSdk(dir);
@@ -201,46 +198,34 @@
}
private static String getPlatformDirFromHostOutSdkSdk(File sdkDir) {
- File[] possibleSdks = sdkDir.listFiles(new FileFilter() {
- @Override
- public boolean accept(File path) {
- return path.isDirectory() && path.getName().contains("android-sdk");
- }
- });
+ File[] possibleSdks = sdkDir.listFiles(
+ path -> path.isDirectory() && path.getName().contains("android-sdk"));
for (File possibleSdk : possibleSdks) {
File platformsDir = new File(possibleSdk, "platforms");
- File[] platforms = platformsDir.listFiles(new FileFilter() {
- @Override
- public boolean accept(File path) {
- return path.isDirectory() && path.getName().startsWith("android-");
- }
- });
+ File[] platforms = platformsDir.listFiles(
+ path -> path.isDirectory() && path.getName().startsWith("android-"));
if (platforms == null || platforms.length == 0) {
continue;
}
- Arrays.sort(platforms, new Comparator<File>() {
- // Codenames before ints. Higher APIs precede lower.
- @Override
- public int compare(File o1, File o2) {
- final int MAX_VALUE = 1000;
- String suffix1 = o1.getName().substring("android-".length());
- String suffix2 = o2.getName().substring("android-".length());
- int suff1, suff2;
- try {
- suff1 = Integer.parseInt(suffix1);
- } catch (NumberFormatException e) {
- suff1 = MAX_VALUE;
- }
- try {
- suff2 = Integer.parseInt(suffix2);
- } catch (NumberFormatException e) {
- suff2 = MAX_VALUE;
- }
- if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) {
- return suff2 - suff1;
- }
- return suffix2.compareTo(suffix1);
+ Arrays.sort(platforms, (o1, o2) -> {
+ final int MAX_VALUE = 1000;
+ String suffix1 = o1.getName().substring("android-".length());
+ String suffix2 = o2.getName().substring("android-".length());
+ int suff1, suff2;
+ try {
+ suff1 = Integer.parseInt(suffix1);
+ } catch (NumberFormatException e) {
+ suff1 = MAX_VALUE;
}
+ try {
+ suff2 = Integer.parseInt(suffix2);
+ } catch (NumberFormatException e) {
+ suff2 = MAX_VALUE;
+ }
+ if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) {
+ return suff2 - suff1;
+ }
+ return suffix2.compareTo(suffix1);
});
return platforms[0].getAbsolutePath();
}
@@ -261,6 +246,7 @@
return null;
}
}
+
/**
* Initialize the bridge and the resource maps.
*/
@@ -325,8 +311,7 @@
@Test
public void testExpand() throws ClassNotFoundException {
// Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
- "expand_vert_layout.xml");
+ LayoutPullParser parser = createLayoutPullParser("expand_vert_layout.xml");
// Create LayoutLibCallback.
LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
layoutLibCallback.initResources();
@@ -348,8 +333,7 @@
.setScreenHeight(300)
.setDensity(Density.XHIGH)
.setNavigation(Navigation.NONAV);
- parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
- "expand_horz_layout.xml");
+ parser = createLayoutPullParser("expand_horz_layout.xml");
params = getSessionParams(parser, customConfigGenerator,
layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
RenderingMode.H_SCROLL, 22);
@@ -361,8 +345,7 @@
@Test
public void testVectorAnimation() throws ClassNotFoundException {
// Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
- "indeterminate_progressbar.xml");
+ LayoutPullParser parser = createLayoutPullParser("indeterminate_progressbar.xml");
// Create LayoutLibCallback.
LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
layoutLibCallback.initResources();
@@ -373,8 +356,7 @@
renderAndVerify(params, "animated_vector.png", TimeUnit.SECONDS.toNanos(2));
- parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
- "indeterminate_progressbar.xml");
+ parser = createLayoutPullParser("indeterminate_progressbar.xml");
params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
RenderingMode.V_SCROLL, 22);
@@ -388,8 +370,7 @@
@Test
public void testVectorDrawable() throws ClassNotFoundException {
// Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
- "vector_drawable.xml");
+ LayoutPullParser parser = createLayoutPullParser("vector_drawable.xml");
// Create LayoutLibCallback.
LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
layoutLibCallback.initResources();
@@ -405,8 +386,7 @@
@Test
public void testScrolling() throws ClassNotFoundException {
// Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
- "scrolled.xml");
+ LayoutPullParser parser = createLayoutPullParser("scrolled.xml");
// Create LayoutLibCallback.
LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
layoutLibCallback.initResources();
@@ -435,6 +415,39 @@
assertEquals(690, rootLayout.getChildren().get(5).getChildren().get(0).getRight());
}
+ @Test
+ public void testGetResourceNameVariants() throws Exception {
+ // Setup
+ SessionParams params = createSessionParams("", ConfigGenerator.NEXUS_4);
+ AssetManager assetManager = AssetManager.getSystem();
+ DisplayMetrics metrics = new DisplayMetrics();
+ Configuration configuration = RenderAction.getConfiguration(params);
+ Resources resources = new Resources(assetManager, metrics, configuration);
+ resources.mLayoutlibCallback = params.getLayoutlibCallback();
+ resources.mContext =
+ new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
+ params.getAssets(), params.getLayoutlibCallback(), configuration,
+ params.getTargetSdkVersion(), params.isRtlSupported());
+ // Test
+ assertEquals("android:style/ButtonBar",
+ resources.getResourceName(android.R.style.ButtonBar));
+ assertEquals("android", resources.getResourcePackageName(android.R.style.ButtonBar));
+ assertEquals("ButtonBar", resources.getResourceEntryName(android.R.style.ButtonBar));
+ assertEquals("style", resources.getResourceTypeName(android.R.style.ButtonBar));
+ int id = resources.mLayoutlibCallback.getResourceId(ResourceType.STRING, "app_name");
+ assertEquals("com.android.layoutlib.test.myapplication:string/app_name",
+ resources.getResourceName(id));
+ assertEquals("com.android.layoutlib.test.myapplication",
+ resources.getResourcePackageName(id));
+ assertEquals("string", resources.getResourceTypeName(id));
+ assertEquals("app_name", resources.getResourceEntryName(id));
+ }
+
+ @NonNull
+ private LayoutPullParser createLayoutPullParser(String layoutPath) {
+ return new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutPath);
+ }
+
/**
* Create a new rendering session and test that rendering the given layout doesn't throw any
* exceptions and matches the provided image.
@@ -505,16 +518,21 @@
private RenderResult renderAndVerify(String layoutFileName, String goldenFileName,
ConfigGenerator deviceConfig)
throws ClassNotFoundException {
+ SessionParams params = createSessionParams(layoutFileName, deviceConfig);
+ return renderAndVerify(params, goldenFileName);
+ }
+
+ private SessionParams createSessionParams(String layoutFileName, ConfigGenerator deviceConfig)
+ throws ClassNotFoundException {
// Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName);
+ LayoutPullParser parser = createLayoutPullParser(layoutFileName);
// Create LayoutLibCallback.
LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
layoutLibCallback.initResources();
// TODO: Set up action bar handler properly to test menu rendering.
// Create session params.
- SessionParams params = getSessionParams(parser, deviceConfig,
+ return getSessionParams(parser, deviceConfig,
layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
- return renderAndVerify(params, goldenFileName);
}
/**
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
index 6c16ed0..96ae523 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
@@ -24,7 +24,9 @@
import com.android.ide.common.rendering.api.ParserFactory;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams.Key;
import com.android.ide.common.resources.IntArrayWrapper;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.resources.ResourceType;
import com.android.util.Pair;
import com.android.utils.ILogger;
@@ -176,4 +178,12 @@
}
};
}
+
+ @Override
+ public <T> T getFlag(Key<T> key) {
+ if (key.equals(RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE)) {
+ return (T) PACKAGE_NAME;
+ }
+ return null;
+ }
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
index c79b662..1110494 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java
@@ -56,9 +56,7 @@
public LayoutPullParser(File layoutFile) {
try {
init(new FileInputStream(layoutFile));
- } catch (XmlPullParserException e) {
- throw new IOError(e);
- } catch (FileNotFoundException e) {
+ } catch (XmlPullParserException | FileNotFoundException e) {
throw new IOError(e);
}
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index c5e7bff..ecf5447 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -277,6 +277,12 @@
* non-zero => scan was truncated, so results may not be complete
*/
private int mFlags;
+ /**
+ * Indicates the buckets that were scanned to generate these results.
+ * This is not relevant to WifiScanner API users and is used internally.
+ * {@hide}
+ */
+ private int mBucketsScanned;
/** all scan results discovered in this scan, sorted by timestamp in ascending order */
private ScanResult mResults[];
@@ -288,9 +294,18 @@
mResults = results;
}
+ /** {@hide} */
+ public ScanData(int id, int flags, int bucketsScanned, ScanResult[] results) {
+ mId = id;
+ mFlags = flags;
+ mBucketsScanned = bucketsScanned;
+ mResults = results;
+ }
+
public ScanData(ScanData s) {
mId = s.mId;
mFlags = s.mFlags;
+ mBucketsScanned = s.mBucketsScanned;
mResults = new ScanResult[s.mResults.length];
for (int i = 0; i < s.mResults.length; i++) {
ScanResult result = s.mResults[i];
@@ -321,6 +336,7 @@
if (mResults != null) {
dest.writeInt(mId);
dest.writeInt(mFlags);
+ dest.writeInt(mBucketsScanned);
dest.writeInt(mResults.length);
for (int i = 0; i < mResults.length; i++) {
ScanResult result = mResults[i];
@@ -337,12 +353,13 @@
public ScanData createFromParcel(Parcel in) {
int id = in.readInt();
int flags = in.readInt();
+ int bucketsScanned = in.readInt();
int n = in.readInt();
ScanResult results[] = new ScanResult[n];
for (int i = 0; i < n; i++) {
results[i] = ScanResult.CREATOR.createFromParcel(in);
}
- return new ScanData(id, flags, results);
+ return new ScanData(id, flags, bucketsScanned, results);
}
public ScanData[] newArray(int size) {