diff options
195 files changed, 4060 insertions, 2056 deletions
diff --git a/api/current.txt b/api/current.txt index 77c64d7e570f..c3a4a0c8919d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24962,6 +24962,7 @@ package android.provider { public static class CallLog.Calls implements android.provider.BaseColumns { ctor public CallLog.Calls(); method public static java.lang.String getLastOutgoingCall(android.content.Context); + field public static final int BLOCKED_TYPE = 6; // 0x6 field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number"; field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri"; field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number"; @@ -25000,6 +25001,7 @@ package android.provider { field public static final int PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int PRESENTATION_RESTRICTED = 2; // 0x2 field public static final int PRESENTATION_UNKNOWN = 3; // 0x3 + field public static final int REJECTED_TYPE = 5; // 0x5 field public static final java.lang.String TRANSCRIPTION = "transcription"; field public static final java.lang.String TYPE = "type"; field public static final int VOICEMAIL_TYPE = 4; // 0x4 diff --git a/api/system-current.txt b/api/system-current.txt index cff0055cba2f..325aa28bef05 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -26918,6 +26918,7 @@ package android.provider { public static class CallLog.Calls implements android.provider.BaseColumns { ctor public CallLog.Calls(); method public static java.lang.String getLastOutgoingCall(android.content.Context); + field public static final int BLOCKED_TYPE = 6; // 0x6 field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number"; field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri"; field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number"; @@ -26956,6 +26957,7 @@ package android.provider { field public static final int PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int PRESENTATION_RESTRICTED = 2; // 0x2 field public static final int PRESENTATION_UNKNOWN = 3; // 0x3 + field public static final int REJECTED_TYPE = 5; // 0x5 field public static final java.lang.String TRANSCRIPTION = "transcription"; field public static final java.lang.String TYPE = "type"; field public static final int VOICEMAIL_TYPE = 4; // 0x4 diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 5c9fd51d606d..4a13136fa8d9 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -44,6 +44,7 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.net.Uri; @@ -63,6 +64,7 @@ import android.util.ArrayMap; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; +import com.android.internal.util.Preconditions; import java.io.BufferedReader; import java.io.File; @@ -168,6 +170,7 @@ public class Am extends BaseCommand { " am get-inactive [--user <USER_ID>] <PACKAGE>\n" + " am send-trim-memory [--user <USER_ID>] <PROCESS>\n" + " [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]\n" + + " am get-current-user\n" + "\n" + "am start: start an Activity. Options are:\n" + " -D: enable debugging\n" + @@ -334,7 +337,9 @@ public class Am extends BaseCommand { "\n" + "am get-inactive: returns the inactive state of an app.\n" + "\n" + - "am send-trim-memory: Send a memory trim event to a <PROCESS>.\n" + + "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + + "\n" + + "am get-current-user: returns id of the current foreground user.\n" + "\n" + "<INTENT> specifications include these flags and arguments:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + @@ -464,6 +469,8 @@ public class Am extends BaseCommand { runGetInactive(); } else if (op.equals("send-trim-memory")) { runSendTrimMemory(); + } else if (op.equals("get-current-user")) { + runGetCurrentUser(); } else { showError("Error: unknown command '" + op + "'"); } @@ -2712,6 +2719,12 @@ public class Am extends BaseCommand { } } + private void runGetCurrentUser() throws Exception { + UserInfo currentUser = Preconditions.checkNotNull(mAm.getCurrentUser(), + "Current user not set"); + System.out.println(currentUser.id); + } + /** * Open the given file for sending into the system process. This verifies * with SELinux that the system will have access to the file. diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 16f825da6f31..d444638c715a 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -603,7 +603,17 @@ public final class AnimatorSet extends Animator { createDependencyGraph(); // Now that all dependencies are set up, start the animations that should be started. - start(mRootNode); + boolean setIsEmpty = false; + if (mStartDelay > 0) { + start(mRootNode); + } else if (mNodes.size() > 1) { + // No delay, but there are other animators in the set + onChildAnimatorEnded(mDelayAnim); + } else { + // Set is empty, no delay, no other animation. Skip to end in this case + setIsEmpty = true; + } + if (mListeners != null) { ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); @@ -612,18 +622,9 @@ public final class AnimatorSet extends Animator { tmpListeners.get(i).onAnimationStart(this); } } - if (mNodes.size() == 0 && mStartDelay == 0) { - // Handle unusual case where empty AnimatorSet is started - should send out - // end event immediately since the event will not be sent out at all otherwise - mStarted = false; - if (mListeners != null) { - ArrayList<AnimatorListener> tmpListeners = - (ArrayList<AnimatorListener>) mListeners.clone(); - int numListeners = tmpListeners.size(); - for (int i = 0; i < numListeners; ++i) { - tmpListeners.get(i).onAnimationEnd(this); - } - } + if (setIsEmpty) { + // In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away. + onChildAnimatorEnded(mDelayAnim); } } @@ -751,44 +752,7 @@ public final class AnimatorSet extends Animator { public void onAnimationEnd(Animator animation) { animation.removeListener(this); mAnimatorSet.mPlayingSet.remove(animation); - Node animNode = mAnimatorSet.mNodeMap.get(animation); - animNode.mEnded = true; - - if (!mAnimatorSet.mTerminated) { - List<Node> children = animNode.mChildNodes; - // Start children animations, if any. - int childrenSize = children == null ? 0 : children.size(); - for (int i = 0; i < childrenSize; i++) { - if (children.get(i).mLatestParent == animNode) { - mAnimatorSet.start(children.get(i)); - } - } - // Listeners are already notified of the AnimatorSet ending in cancel() or - // end(); the logic below only kicks in when animations end normally - boolean allDone = true; - // Traverse the tree and find if there's any unfinished node - int size = mAnimatorSet.mNodes.size(); - for (int i = 0; i < size; i++) { - if (!mAnimatorSet.mNodes.get(i).mEnded) { - allDone = false; - break; - } - } - if (allDone) { - // If this was the last child animation to end, then notify listeners that this - // AnimatorSet has ended - if (mAnimatorSet.mListeners != null) { - ArrayList<AnimatorListener> tmpListeners = - (ArrayList<AnimatorListener>) mAnimatorSet.mListeners.clone(); - int numListeners = tmpListeners.size(); - for (int i = 0; i < numListeners; ++i) { - tmpListeners.get(i).onAnimationEnd(mAnimatorSet); - } - } - mAnimatorSet.mStarted = false; - mAnimatorSet.mPaused = false; - } - } + mAnimatorSet.onChildAnimatorEnded(animation); } // Nothing to do @@ -801,6 +765,47 @@ public final class AnimatorSet extends Animator { } + private void onChildAnimatorEnded(Animator animation) { + Node animNode = mNodeMap.get(animation); + animNode.mEnded = true; + + if (!mTerminated) { + List<Node> children = animNode.mChildNodes; + // Start children animations, if any. + int childrenSize = children == null ? 0 : children.size(); + for (int i = 0; i < childrenSize; i++) { + if (children.get(i).mLatestParent == animNode) { + start(children.get(i)); + } + } + // Listeners are already notified of the AnimatorSet ending in cancel() or + // end(); the logic below only kicks in when animations end normally + boolean allDone = true; + // Traverse the tree and find if there's any unfinished node + int size = mNodes.size(); + for (int i = 0; i < size; i++) { + if (!mNodes.get(i).mEnded) { + allDone = false; + break; + } + } + if (allDone) { + // If this was the last child animation to end, then notify listeners that this + // AnimatorSet has ended + if (mListeners != null) { + ArrayList<AnimatorListener> tmpListeners = + (ArrayList<AnimatorListener>) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationEnd(this); + } + } + mStarted = false; + mPaused = false; + } + } + } + /** * @hide */ diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 5af6504ff699..1995ef58e499 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -932,6 +932,13 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio updateScaledDuration(); // in case the scale factor has changed since creation time AnimationHandler animationHandler = AnimationHandler.getInstance(); animationHandler.addAnimationFrameCallback(this, mStartDelay); + + if (mStartDelay == 0) { + // If there's no start delay, init the animation and notify start listeners right away + // Otherwise, postpone this until the first frame after the start delay. + startAnimation(); + setCurrentFraction(mSeekFraction == -1 ? 0 : mSeekFraction); + } } @Override @@ -1075,6 +1082,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio mStartListenersCalled = false; mPlayingBackwards = false; mReversing = false; + mLastFrameTime = 0; mCurrentIteration = 0; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), @@ -1184,12 +1192,13 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * @hide */ public final void doAnimationFrame(long frameTime) { - mLastFrameTime = frameTime; AnimationHandler handler = AnimationHandler.getInstance(); - if (!mRunning) { + if (mLastFrameTime == 0) { // First frame handler.addOneShotCommitCallback(this); - startAnimation(); + if (mStartDelay > 0) { + startAnimation(); + } if (mSeekFraction < 0) { mStartTime = frameTime; } else { @@ -1199,6 +1208,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio } mStartTimeCommitted = false; // allow start time to be compensated for jank } + mLastFrameTime = frameTime; if (mPaused) { if (mPauseTime < 0) { mPauseTime = frameTime; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index e965d654fcc7..3f566eb92756 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1545,7 +1545,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> /** * <p>Whether video stabilization is * active.</p> - * <p>Video stabilization automatically translates and scales images from + * <p>Video stabilization automatically warps images from * the camera in order to stabilize motion between consecutive frames.</p> * <p>If enabled, video stabilization can modify the * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p> @@ -1555,6 +1555,15 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * the video stabilization modes in the first several capture results may * still be "OFF", and it will become "ON" when the initialization is * done.</p> + * <p>In addition, not all recording sizes or frame rates may be supported for + * stabilization by a device that reports stabilization support. It is guaranteed + * that an output targeting a MediaRecorder or MediaCodec will be stabilized if + * the recording resolution is less than or equal to 1920 x 1080 (width less than + * or equal to 1920, height less than or equal to 1080), and the recording + * frame rate is less than or equal to 30fps. At other sizes, the CaptureResult + * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return + * OFF if the recording output is not stabilized, or if there are no output + * Surface types that can be stabilized.</p> * <p>If a camera device supports both this mode and OIS * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may * produce undesirable interaction, so it is recommended not to enable @@ -1566,6 +1575,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * </ul></p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 46eddb3f6651..b3acf2b09784 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2056,7 +2056,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>Whether video stabilization is * active.</p> - * <p>Video stabilization automatically translates and scales images from + * <p>Video stabilization automatically warps images from * the camera in order to stabilize motion between consecutive frames.</p> * <p>If enabled, video stabilization can modify the * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p> @@ -2066,6 +2066,15 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * the video stabilization modes in the first several capture results may * still be "OFF", and it will become "ON" when the initialization is * done.</p> + * <p>In addition, not all recording sizes or frame rates may be supported for + * stabilization by a device that reports stabilization support. It is guaranteed + * that an output targeting a MediaRecorder or MediaCodec will be stabilized if + * the recording resolution is less than or equal to 1920 x 1080 (width less than + * or equal to 1920, height less than or equal to 1080), and the recording + * frame rate is less than or equal to 30fps. At other sizes, the CaptureResult + * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return + * OFF if the recording output is not stabilized, or if there are no output + * Surface types that can be stabilized.</p> * <p>If a camera device supports both this mode and OIS * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may * produce undesirable interaction, so it is recommended not to enable @@ -2077,6 +2086,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * </ul></p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index c3733085caf6..cd483b104489 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -19,6 +19,7 @@ package android.os; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.Log; +import android.util.MathUtils; import java.io.Serializable; import java.util.ArrayList; @@ -1345,18 +1346,19 @@ public class BaseBundle { */ void readFromParcelInner(Parcel parcel) { int length = parcel.readInt(); - if (length < 0) { - throw new RuntimeException("Bad length in parcel: " + length); - } readFromParcelInner(parcel, length); } private void readFromParcelInner(Parcel parcel, int length) { - if (length == 0) { + if (length < 0) { + throw new RuntimeException("Bad length in parcel: " + length); + + } else if (length == 0) { // Empty Bundle or end of data. mParcelledData = EMPTY_PARCEL; return; } + int magic = parcel.readInt(); if (magic != BUNDLE_MAGIC) { //noinspection ThrowableInstanceNeverThrown @@ -1366,7 +1368,7 @@ public class BaseBundle { // Advance within this Parcel int offset = parcel.dataPosition(); - parcel.setDataPosition(offset + length); + parcel.setDataPosition(MathUtils.addOrThrow(offset, length)); Parcel p = Parcel.obtain(); p.setDataPosition(0); diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java index 11785f1072fd..5bbe6488d514 100644 --- a/core/java/android/os/ParcelableParcel.java +++ b/core/java/android/os/ParcelableParcel.java @@ -16,6 +16,8 @@ package android.os; +import android.util.MathUtils; + /** * Parcelable containing a raw Parcel of data. * @hide @@ -33,9 +35,13 @@ public class ParcelableParcel implements Parcelable { mParcel = Parcel.obtain(); mClassLoader = loader; int size = src.readInt(); + if (size < 0) { + throw new IllegalArgumentException("Negative size read from parcel"); + } + int pos = src.dataPosition(); - mParcel.appendFrom(src, src.dataPosition(), size); - src.setDataPosition(pos + size); + src.setDataPosition(MathUtils.addOrThrow(pos, size)); + mParcel.appendFrom(src, pos, size); } public Parcel getParcel() { diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 4f880b1275e4..342f8c77d6ee 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -153,6 +153,18 @@ public class CallLog { /** * The type of the call (incoming, outgoing or missed). * <P>Type: INTEGER (int)</P> + * + * <p> + * Allowed values: + * <ul> + * <li>{@link #INCOMING_TYPE}</li> + * <li>{@link #OUTGOING_TYPE}</li> + * <li>{@link #MISSED_TYPE}</li> + * <li>{@link #VOICEMAIL_TYPE}</li> + * <li>{@link #REJECTED_TYPE}</li> + * <li>{@link #BLOCKED_TYPE}</li> + * </ul> + * </p> */ public static final String TYPE = "type"; @@ -164,6 +176,10 @@ public class CallLog { public static final int MISSED_TYPE = 3; /** Call log type for voicemails. */ public static final int VOICEMAIL_TYPE = 4; + /** Call log type for calls rejected by direct user action. */ + public static final int REJECTED_TYPE = 5; + /** Call log type for calls blocked automatically. */ + public static final int BLOCKED_TYPE = 6; /** * Bit-mask describing features of the call (e.g. video). diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 8b57d3d3d6c4..32aac13d39b4 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -156,6 +156,27 @@ public final class MathUtils { return start + (stop - start) * amount; } + /** + * Returns an interpolated angle in degrees between a set of start and end + * angles. + * <p> + * Unlike {@link #lerp(float, float, float)}, the direction and distance of + * travel is determined by the shortest angle between the start and end + * angles. For example, if the starting angle is 0 and the ending angle is + * 350, then the interpolated angle will be in the range [0,-10] rather + * than [0,350]. + * + * @param start the starting angle in degrees + * @param end the ending angle in degrees + * @param amount the position between start and end in the range [0,1] + * where 0 is the starting angle and 1 is the ending angle + * @return the interpolated angle in degrees + */ + public static float lerpDeg(float start, float end, float amount) { + final float minAngle = (((end - start) + 180) % 360) - 180; + return minAngle * amount + start; + } + public static float norm(float start, float stop, float value) { return (value - start) / (stop - start); } @@ -185,4 +206,24 @@ public final class MathUtils { public static void randomSeed(long seed) { sRandom.setSeed(seed); } + + /** + * Returns the sum of the two parameters, or throws an exception if the resulting sum would + * cause an overflow or underflow. + * @throws IllegalArgumentException when overflow or underflow would occur. + */ + public static int addOrThrow(int a, int b) throws IllegalArgumentException { + if (b == 0) { + return a; + } + + if (b > 0 && a <= (Integer.MAX_VALUE - b)) { + return a + b; + } + + if (b < 0 && a >= (Integer.MIN_VALUE - b)) { + return a + b; + } + throw new IllegalArgumentException("Addition overflow: " + a + " + " + b); + } } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index dcef14267b7f..304e9c048b60 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -349,7 +349,7 @@ public class ThreadedRenderer extends HardwareRenderer { * @param right The right side of the protected bounds. * @param bottom The bottom side of the protected bounds. */ - public void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) { + public void setContentDrawBounds(int left, int top, int right, int bottom) { mStagedContentBounds.set(left, top, right, bottom); } @@ -370,9 +370,9 @@ public class ThreadedRenderer extends HardwareRenderer { // renderer. if (!mCurrentContentBounds.equals(mStagedContentBounds)) { mCurrentContentBounds.set(mStagedContentBounds); - nSetContentOverdrawProtectionBounds(mNativeProxy, mCurrentContentBounds.left, - mCurrentContentBounds.top, mCurrentContentBounds.right, - mCurrentContentBounds.bottom); + nSetContentDrawBounds(mNativeProxy, mCurrentContentBounds.left, + mCurrentContentBounds.top, mCurrentContentBounds.right, + mCurrentContentBounds.bottom); } attachInfo.mIgnoreDirtyState = false; @@ -600,6 +600,6 @@ public class ThreadedRenderer extends HardwareRenderer { boolean placeFront); private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode); private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode); - private static native void nSetContentOverdrawProtectionBounds(long nativeProxy, int left, + private static native void nSetContentDrawBounds(long nativeProxy, int left, int top, int right, int bottom); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f6c60ed688a5..7cf23e717f6e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -73,6 +73,7 @@ import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.view.WindowCallbacks; import android.widget.Scroller; import com.android.internal.R; @@ -115,6 +116,12 @@ public final class ViewRootImpl implements ViewParent, private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV; /** + * Set to false if we do not want to use the multi threaded renderer. Note that by disabling + * this, WindowCallbacks will not fire. + */ + private static final boolean USE_MT_RENDERER = true; + + /** * Set this system property to true to force the view hierarchy to render * at 60 Hz. This can be used to measure the potential framerate. */ @@ -132,11 +139,11 @@ public final class ViewRootImpl implements ViewParent, static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); - static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>(); + static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList(); static boolean sFirstDrawComplete = false; + static final ArrayList<WindowCallbacks> sWindowCallbacks = new ArrayList(); - static final ArrayList<ComponentCallbacks> sConfigCallbacks - = new ArrayList<ComponentCallbacks>(); + static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList(); final Context mContext; final IWindowSession mWindowSession; @@ -417,6 +424,22 @@ public final class ViewRootImpl implements ViewParent, } } + public static void addWindowCallbacks(WindowCallbacks callback) { + if (USE_MT_RENDERER) { + synchronized (sWindowCallbacks) { + sWindowCallbacks.add(callback); + } + } + } + + public static void removeWindowCallbacks(WindowCallbacks callback) { + if (USE_MT_RENDERER) { + synchronized (sWindowCallbacks) { + sWindowCallbacks.remove(callback); + } + } + } + // FIXME for perf testing only private boolean mProfile = false; @@ -1378,6 +1401,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mWindowVisibility = viewVisibility; host.dispatchWindowVisibilityChanged(viewVisibility); if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { + endDragResizing(); destroyHardwareResources(); } if (viewVisibility == View.GONE) { @@ -1701,14 +1725,20 @@ public final class ViewRootImpl implements ViewParent, final boolean dragResizing = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING) != 0; if (mDragResizing != dragResizing) { - mDragResizing = dragResizing; - mFullRedrawNeeded = true; + if (dragResizing) { + startDragResizing(frame); + } else { + // We shouldn't come here, but if we come we should end the resize. + endDragResizing(); + } } - if (dragResizing) { - mCanvasOffsetX = mWinFrame.left; - mCanvasOffsetY = mWinFrame.top; - } else { - mCanvasOffsetX = mCanvasOffsetY = 0; + if (!USE_MT_RENDERER) { + if (dragResizing) { + mCanvasOffsetX = mWinFrame.left; + mCanvasOffsetY = mWinFrame.top; + } else { + mCanvasOffsetX = mCanvasOffsetY = 0; + } } } catch (RemoteException e) { } @@ -6635,6 +6665,15 @@ public final class ViewRootImpl implements ViewParent, Configuration newConfig) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { + // Tell all listeners that we are resizing the window so that the chrome can get + // updated as fast as possible on a separate thread, + if (mViewAncestor.get().mDragResizing) { + synchronized (sWindowCallbacks) { + for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) { + sWindowCallbacks.get(i).onWindowSizeIsChanging(frame); + } + } + } viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets, reportDraw, newConfig); } @@ -6804,6 +6843,36 @@ public final class ViewRootImpl implements ViewParent, } /** + * Start a drag resizing which will inform all listeners that a window resize is taking place. + */ + private void startDragResizing(Rect initialBounds) { + if (!mDragResizing) { + mDragResizing = true; + synchronized (sWindowCallbacks) { + for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) { + sWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds); + } + } + mFullRedrawNeeded = true; + } + } + + /** + * End a drag resize which will inform all listeners that a window resize has ended. + */ + private void endDragResizing() { + if (mDragResizing) { + mDragResizing = false; + synchronized (sWindowCallbacks) { + for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) { + sWindowCallbacks.get(i).onWindowDragResizeEnd(); + } + } + mFullRedrawNeeded = true; + } + } + + /** * Class for managing the accessibility interaction connection * based on the global accessibility state. */ diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java new file mode 100644 index 000000000000..cb6e98353a59 --- /dev/null +++ b/core/java/android/view/WindowCallbacks.java @@ -0,0 +1,48 @@ +/* + * 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 android.view; + +import android.graphics.Rect; + +/** + * These callbacks are used to communicate window configuration changes while the user is performing + * window changes. + * @hide + */ +public interface WindowCallbacks { + /** + * Called by the system when the window got changed by the user, before the layouter got called. + * It can be used to perform a "quick and dirty" resize which should never take more then 4ms to + * complete. + * + * <p>At the time the layouting has not happened yet. + * + * @param newBounds The new window frame bounds. + */ + void onWindowSizeIsChanging(Rect newBounds); + + /** + * Called when a drag resize starts. + * @param initialBounds The initial bounds where the window will be. + */ + void onWindowDragResizeStart(Rect initialBounds); + + /** + * Called when a drag resize ends. + */ + void onWindowDragResizeEnd(); +} diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 72971e85dd24..81ec3306c4c7 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -88,6 +88,9 @@ public final class AccessibilityManager { /** @hide */ public static final int DALTONIZER_CORRECT_DEUTERANOMALY = 12; + /** @hide */ + public static final int AUTOCLICK_DELAY_DEFAULT = 600; + static final Object sInstanceSync = new Object(); private static AccessibilityManager sInstance; diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 95711092a39b..72202567d9bd 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -16,12 +16,7 @@ package android.widget; -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.Keyframe; import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; @@ -35,6 +30,7 @@ import android.graphics.Region; import android.graphics.Typeface; import android.os.Bundle; import android.util.AttributeSet; +import android.util.FloatProperty; import android.util.IntArray; import android.util.Log; import android.util.MathUtils; @@ -50,7 +46,6 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; import com.android.internal.widget.ExploreByTouchHelper; -import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; @@ -60,6 +55,7 @@ import java.util.Locale; * @hide */ public class RadialTimePickerView extends View { + private static final String TAG = "RadialTimePickerView"; private static final int HOURS = 0; @@ -73,12 +69,6 @@ public class RadialTimePickerView extends View { private static final int AM = 0; private static final int PM = 1; - // Opaque alpha level - private static final int ALPHA_OPAQUE = 255; - - // Transparent alpha level - private static final int ALPHA_TRANSPARENT = 0; - private static final int HOURS_IN_CIRCLE = 12; private static final int MINUTES_IN_CIRCLE = 60; private static final int DEGREES_FOR_ONE_HOUR = 360 / HOURS_IN_CIRCLE; @@ -88,8 +78,8 @@ public class RadialTimePickerView extends View { private static final int[] HOURS_NUMBERS_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; private static final int[] MINUTES_NUMBERS = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55}; - private static final int FADE_OUT_DURATION = 500; - private static final int FADE_IN_DURATION = 500; + private static final int ANIM_DURATION_NORMAL = 500; + private static final int ANIM_DURATION_TOUCH = 60; private static final int[] SNAP_PREFER_30S_MAP = new int[361]; @@ -97,6 +87,9 @@ public class RadialTimePickerView extends View { private static final float[] COS_30 = new float[NUM_POSITIONS]; private static final float[] SIN_30 = new float[NUM_POSITIONS]; + /** "Something is wrong" color used when a color attribute is missing. */ + private static final int MISSING_COLOR = Color.MAGENTA; + static { // Prepare mapping to snap touchable degrees to selectable degrees. preparePrefer30sMap(); @@ -110,8 +103,19 @@ public class RadialTimePickerView extends View { } } - private final InvalidateUpdateListener mInvalidateUpdateListener = - new InvalidateUpdateListener(); + private final FloatProperty<RadialTimePickerView> HOURS_TO_MINUTES = + new FloatProperty<RadialTimePickerView>("hoursToMinutes") { + @Override + public Float get(RadialTimePickerView radialTimePickerView) { + return radialTimePickerView.mHoursToMinutes; + } + + @Override + public void setValue(RadialTimePickerView object, float value) { + object.mHoursToMinutes = value; + object.invalidate(); + } + }; private final String[] mHours12Texts = new String[12]; private final String[] mOuterHours24Texts = new String[12]; @@ -119,15 +123,8 @@ public class RadialTimePickerView extends View { private final String[] mMinutesTexts = new String[12]; private final Paint[] mPaint = new Paint[2]; - private final IntHolder[] mAlpha = new IntHolder[2]; - private final Paint mPaintCenter = new Paint(); - - private final Paint[][] mPaintSelector = new Paint[2][3]; - - private final int mSelectorColor; - private final int mSelectorDotColor; - + private final Paint[] mPaintSelector = new Paint[3]; private final Paint mPaintBackground = new Paint(); private final Typeface mTypeface; @@ -144,9 +141,6 @@ public class RadialTimePickerView extends View { private final int[] mSelectionDegrees = new int[2]; - private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<>(); - private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<>(); - private final RadialPickerTouchHelper mTouchHelper; private final Path mSelectorPath = new Path(); @@ -154,6 +148,9 @@ public class RadialTimePickerView extends View { private boolean mIs24HourMode; private boolean mShowHours; + private ObjectAnimator mHoursToMinutesAnimator; + private float mHoursToMinutes; + /** * When in 24-hour mode, indicates that the current hour is between * 1 and 12 (inclusive). @@ -165,6 +162,9 @@ public class RadialTimePickerView extends View { private int mSelectorDotRadius; private int mCenterDotRadius; + private int mSelectorColor; + private int mSelectorDotColor; + private int mXCenter; private int mYCenter; private int mCircleRadius; @@ -176,7 +176,6 @@ public class RadialTimePickerView extends View { private String[] mOuterTextHours; private String[] mInnerTextHours; private String[] mMinutesText; - private AnimatorSet mTransition; private int mAmOrPm; @@ -304,27 +303,15 @@ public class RadialTimePickerView extends View { Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs); + applyAttributes(attrs, defStyleAttr, defStyleRes); + // Pull disabled alpha from theme. final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true); mDisabledAlpha = outValue.getFloat(); - // process style attributes - final Resources res = getResources(); - final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker, - defStyleAttr, defStyleRes); - mTypeface = Typeface.create("sans-serif", Typeface.NORMAL); - // Initialize all alpha values to opaque. - for (int i = 0; i < mAlpha.length; i++) { - mAlpha[i] = new IntHolder(ALPHA_OPAQUE); - } - - mTextColor[HOURS] = a.getColorStateList(R.styleable.TimePicker_numbersTextColor); - mTextColor[HOURS_INNER] = a.getColorStateList(R.styleable.TimePicker_numbersInnerTextColor); - mTextColor[MINUTES] = mTextColor[HOURS]; - mPaint[HOURS] = new Paint(); mPaint[HOURS].setAntiAlias(true); mPaint[HOURS].setTextAlign(Paint.Align.CENTER); @@ -333,44 +320,21 @@ public class RadialTimePickerView extends View { mPaint[MINUTES].setAntiAlias(true); mPaint[MINUTES].setTextAlign(Paint.Align.CENTER); - final ColorStateList selectorColors = a.getColorStateList( - R.styleable.TimePicker_numbersSelectorColor); - final int selectorActivatedColor = selectorColors.getColorForState( - StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); - - mPaintCenter.setColor(selectorActivatedColor); mPaintCenter.setAntiAlias(true); - final int[] activatedStateSet = StateSet.get( - StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED); - - mSelectorColor = selectorActivatedColor; - mSelectorDotColor = mTextColor[HOURS].getColorForState(activatedStateSet, 0); - - mPaintSelector[HOURS][SELECTOR_CIRCLE] = new Paint(); - mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true); - - mPaintSelector[HOURS][SELECTOR_DOT] = new Paint(); - mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true); - - mPaintSelector[HOURS][SELECTOR_LINE] = new Paint(); - mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true); - mPaintSelector[HOURS][SELECTOR_LINE].setStrokeWidth(2); + mPaintSelector[SELECTOR_CIRCLE] = new Paint(); + mPaintSelector[SELECTOR_CIRCLE].setAntiAlias(true); - mPaintSelector[MINUTES][SELECTOR_CIRCLE] = new Paint(); - mPaintSelector[MINUTES][SELECTOR_CIRCLE].setAntiAlias(true); + mPaintSelector[SELECTOR_DOT] = new Paint(); + mPaintSelector[SELECTOR_DOT].setAntiAlias(true); - mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint(); - mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true); + mPaintSelector[SELECTOR_LINE] = new Paint(); + mPaintSelector[SELECTOR_LINE].setAntiAlias(true); + mPaintSelector[SELECTOR_LINE].setStrokeWidth(2); - mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint(); - mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true); - mPaintSelector[MINUTES][SELECTOR_LINE].setStrokeWidth(2); - - mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor, - context.getColor(R.color.timepicker_default_numbers_background_color_material))); mPaintBackground.setAntiAlias(true); + final Resources res = getResources(); mSelectorRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_radius); mSelectorStroke = res.getDimensionPixelSize(R.dimen.timepicker_selector_stroke); mSelectorDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_dot_radius); @@ -385,6 +349,7 @@ public class RadialTimePickerView extends View { mTextInset[HOURS_INNER] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_inner); mShowHours = true; + mHoursToMinutes = HOURS; mIs24HourMode = false; mAmOrPm = AM; @@ -399,8 +364,6 @@ public class RadialTimePickerView extends View { initHoursAndMinutesText(); initData(); - a.recycle(); - // Initial values final Calendar calendar = Calendar.getInstance(Locale.getDefault()); final int currentHour = calendar.get(Calendar.HOUR_OF_DAY); @@ -412,6 +375,48 @@ public class RadialTimePickerView extends View { setHapticFeedbackEnabled(true); } + void applyAttributes(AttributeSet attrs, int defStyleAttr, int defStyleRes) { + final Context context = getContext(); + final TypedArray a = getContext().obtainStyledAttributes(attrs, + R.styleable.TimePicker, defStyleAttr, defStyleRes); + + final ColorStateList numbersTextColor = a.getColorStateList( + R.styleable.TimePicker_numbersTextColor); + final ColorStateList numbersInnerTextColor = a.getColorStateList( + R.styleable.TimePicker_numbersInnerTextColor); + mTextColor[HOURS] = numbersTextColor == null ? + ColorStateList.valueOf(MISSING_COLOR) : numbersTextColor; + mTextColor[HOURS_INNER] = numbersInnerTextColor == null ? + ColorStateList.valueOf(MISSING_COLOR) : numbersInnerTextColor; + mTextColor[MINUTES] = mTextColor[HOURS]; + + // Set up various colors derived from the selector "activated" state. + final ColorStateList selectorColors = a.getColorStateList( + R.styleable.TimePicker_numbersSelectorColor); + final int selectorActivatedColor; + if (selectorColors != null) { + final int[] stateSetEnabledActivated = StateSet.get( + StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED); + selectorActivatedColor = selectorColors.getColorForState( + stateSetEnabledActivated, 0); + } else { + selectorActivatedColor = MISSING_COLOR; + } + + mPaintCenter.setColor(selectorActivatedColor); + + final int[] stateSetActivated = StateSet.get( + StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED); + + mSelectorColor = selectorActivatedColor; + mSelectorDotColor = mTextColor[HOURS].getColorForState(stateSetActivated, 0); + + mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor, + context.getColor(R.color.timepicker_default_numbers_background_color_material))); + + a.recycle(); + } + public void initialize(int hour, int minute, boolean is24HourMode) { if (mIs24HourMode != is24HourMode) { mIs24HourMode = is24HourMode; @@ -569,35 +574,11 @@ public class RadialTimePickerView extends View { } public void showHours(boolean animate) { - if (mShowHours) { - return; - } - - mShowHours = true; - - if (animate) { - startMinutesToHoursAnimation(); - } - - initData(); - invalidate(); - mTouchHelper.invalidateRoot(); + showPicker(true, animate); } public void showMinutes(boolean animate) { - if (!mShowHours) { - return; - } - - mShowHours = false; - - if (animate) { - startHoursToMinutesAnimation(); - } - - initData(); - invalidate(); - mTouchHelper.invalidateRoot(); + showPicker(false, animate); } private void initHoursAndMinutesText() { @@ -620,12 +601,6 @@ public class RadialTimePickerView extends View { } mMinutesText = mMinutesTexts; - - final int hoursAlpha = mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT; - mAlpha[HOURS].setValue(hoursAlpha); - - final int minutesAlpha = mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE; - mAlpha[MINUTES].setValue(minutesAlpha); } @Override @@ -653,90 +628,144 @@ public class RadialTimePickerView extends View { final float alphaMod = mInputEnabled ? 1 : mDisabledAlpha; drawCircleBackground(canvas); - drawHours(canvas, alphaMod); - drawMinutes(canvas, alphaMod); + + final Path selectorPath = mSelectorPath; + drawSelector(canvas, selectorPath); + drawHours(canvas, selectorPath, alphaMod); + drawMinutes(canvas, selectorPath, alphaMod); drawCenter(canvas, alphaMod); } + private void showPicker(boolean hours, boolean animate) { + if (mShowHours == hours) { + return; + } + + mShowHours = hours; + + if (animate) { + animatePicker(hours, ANIM_DURATION_NORMAL); + } + + initData(); + invalidate(); + mTouchHelper.invalidateRoot(); + } + + private void animatePicker(boolean hoursToMinutes, long duration) { + final float target = hoursToMinutes ? HOURS : MINUTES; + if (mHoursToMinutes == target) { + // If we have a pending or running animator, cancel it. + if (mHoursToMinutesAnimator != null && mHoursToMinutesAnimator.isStarted()) { + mHoursToMinutesAnimator.cancel(); + mHoursToMinutesAnimator = null; + } + + // We're already showing the correct picker. + return; + } + + mHoursToMinutesAnimator = ObjectAnimator.ofFloat(this, HOURS_TO_MINUTES, target); + mHoursToMinutesAnimator.setAutoCancel(true); + mHoursToMinutesAnimator.setDuration(duration); + mHoursToMinutesAnimator.start(); + } + private void drawCircleBackground(Canvas canvas) { canvas.drawCircle(mXCenter, mYCenter, mCircleRadius, mPaintBackground); } - private void drawHours(Canvas canvas, float alphaMod) { - final int hoursAlpha = (int) (mAlpha[HOURS].getValue() * alphaMod + 0.5f); + private void drawHours(Canvas canvas, Path selectorPath, float alphaMod) { + final int hoursAlpha = (int) (255f * (1f - mHoursToMinutes) * alphaMod + 0.5f); if (hoursAlpha > 0) { - // Draw the hour selector under the elements. - drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS, null, alphaMod); - - // Draw outer hours. - drawTextElements(canvas, mTextSize[HOURS], mTypeface, mTextColor[HOURS], - mOuterTextHours, mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS], - hoursAlpha, !mIsOnInnerCircle, mSelectionDegrees[HOURS], false); - - // Draw inner hours (13-00) for 24-hour time. - if (mIs24HourMode && mInnerTextHours != null) { - drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mTextColor[HOURS_INNER], - mInnerTextHours, mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha, - mIsOnInnerCircle, mSelectionDegrees[HOURS], false); - } + // Exclude the selector region, then draw inner/outer hours with no + // activated states. + canvas.save(Canvas.CLIP_SAVE_FLAG); + canvas.clipPath(selectorPath, Region.Op.DIFFERENCE); + drawHoursClipped(canvas, hoursAlpha, false); + canvas.restore(); + + // Intersect the selector region, then draw minutes with only + // activated states. + canvas.save(Canvas.CLIP_SAVE_FLAG); + canvas.clipPath(selectorPath, Region.Op.INTERSECT); + drawHoursClipped(canvas, hoursAlpha, true); + canvas.restore(); } } - private void drawMinutes(Canvas canvas, float alphaMod) { - final int minutesAlpha = (int) (mAlpha[MINUTES].getValue() * alphaMod + 0.5f); - if (minutesAlpha > 0) { - // Draw the minute selector under the elements. - drawSelector(canvas, MINUTES, mSelectorPath, alphaMod); + private void drawHoursClipped(Canvas canvas, int hoursAlpha, boolean showActivated) { + // Draw outer hours. + drawTextElements(canvas, mTextSize[HOURS], mTypeface, mTextColor[HOURS], mOuterTextHours, + mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS], hoursAlpha, + showActivated && !mIsOnInnerCircle, mSelectionDegrees[HOURS], showActivated); + // Draw inner hours (13-00) for 24-hour time. + if (mIs24HourMode && mInnerTextHours != null) { + drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mTextColor[HOURS_INNER], + mInnerTextHours, mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha, + showActivated && mIsOnInnerCircle, mSelectionDegrees[HOURS], showActivated); + } + } + + private void drawMinutes(Canvas canvas, Path selectorPath, float alphaMod) { + final int minutesAlpha = (int) (255f * mHoursToMinutes * alphaMod + 0.5f); + if (minutesAlpha > 0) { // Exclude the selector region, then draw minutes with no // activated states. canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipPath(mSelectorPath, Region.Op.DIFFERENCE); - drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES], - mMinutesText, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES], - minutesAlpha, false, 0, false); + canvas.clipPath(selectorPath, Region.Op.DIFFERENCE); + drawMinutesClipped(canvas, minutesAlpha, false); canvas.restore(); // Intersect the selector region, then draw minutes with only // activated states. canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipPath(mSelectorPath, Region.Op.INTERSECT); - drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES], - mMinutesText, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES], - minutesAlpha, true, mSelectionDegrees[MINUTES], true); + canvas.clipPath(selectorPath, Region.Op.INTERSECT); + drawMinutesClipped(canvas, minutesAlpha, true); canvas.restore(); } } + private void drawMinutesClipped(Canvas canvas, int minutesAlpha, boolean showActivated) { + drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES], mMinutesText, + mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES], minutesAlpha, + showActivated, mSelectionDegrees[MINUTES], showActivated); + } + private void drawCenter(Canvas canvas, float alphaMod) { mPaintCenter.setAlpha((int) (255 * alphaMod + 0.5f)); canvas.drawCircle(mXCenter, mYCenter, mCenterDotRadius, mPaintCenter); } - private int applyAlpha(int argb, int alpha) { - final int srcAlpha = (argb >> 24) & 0xFF; - final int dstAlpha = (int) (srcAlpha * (alpha / 255.0) + 0.5f); - return (0xFFFFFF & argb) | (dstAlpha << 24); - } - private int getMultipliedAlpha(int argb, int alpha) { return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5); } - private void drawSelector(Canvas canvas, int index, Path selectorPath, float alphaMod) { - final int alpha = (int) (mAlpha[index % 2].getValue() * alphaMod + 0.5f); - final int color = applyAlpha(mSelectorColor, alpha); + private void drawSelector(Canvas canvas, Path selectorPath) { + // Determine the current length, angle, and dot scaling factor. + final int hoursIndex = mIsOnInnerCircle ? HOURS_INNER : HOURS; + final int hoursInset = mTextInset[hoursIndex]; + final int hoursAngleDeg = mSelectionDegrees[hoursIndex % 2]; + final float hoursDotScale = mSelectionDegrees[hoursIndex % 2] % 30 != 0 ? 1 : 0; + + final int minutesIndex = MINUTES; + final int minutesInset = mTextInset[minutesIndex]; + final int minutesAngleDeg = mSelectionDegrees[minutesIndex]; + final float minutesDotScale = mSelectionDegrees[minutesIndex] % 30 != 0 ? 1 : 0; // Calculate the current radius at which to place the selection circle. final int selRadius = mSelectorRadius; - final int selLength = mCircleRadius - mTextInset[index]; - final double selAngleRad = Math.toRadians(mSelectionDegrees[index % 2]); + final float selLength = + mCircleRadius - MathUtils.lerp(hoursInset, minutesInset, mHoursToMinutes); + final double selAngleRad = + Math.toRadians(MathUtils.lerpDeg(hoursAngleDeg, minutesAngleDeg, mHoursToMinutes)); final float selCenterX = mXCenter + selLength * (float) Math.sin(selAngleRad); final float selCenterY = mYCenter - selLength * (float) Math.cos(selAngleRad); // Draw the selection circle. - final Paint paint = mPaintSelector[index % 2][SELECTOR_CIRCLE]; - paint.setColor(color); + final Paint paint = mPaintSelector[SELECTOR_CIRCLE]; + paint.setColor(mSelectorColor); canvas.drawCircle(selCenterX, selCenterY, selRadius, paint); // If needed, set up the clip path for later. @@ -746,26 +775,26 @@ public class RadialTimePickerView extends View { } // Draw the dot if we're between two items. - final boolean shouldDrawDot = mSelectionDegrees[index % 2] % 30 != 0; - if (shouldDrawDot) { - final Paint dotPaint = mPaintSelector[index % 2][SELECTOR_DOT]; + final float dotScale = MathUtils.lerp(hoursDotScale, minutesDotScale, mHoursToMinutes); + if (dotScale > 0) { + final Paint dotPaint = mPaintSelector[SELECTOR_DOT]; dotPaint.setColor(mSelectorDotColor); - canvas.drawCircle(selCenterX, selCenterY, mSelectorDotRadius, dotPaint); + canvas.drawCircle(selCenterX, selCenterY, mSelectorDotRadius * dotScale, dotPaint); } // Shorten the line to only go from the edge of the center dot to the // edge of the selection circle. final double sin = Math.sin(selAngleRad); final double cos = Math.cos(selAngleRad); - final int lineLength = selLength - selRadius; + final float lineLength = selLength - selRadius; final int centerX = mXCenter + (int) (mCenterDotRadius * sin); final int centerY = mYCenter - (int) (mCenterDotRadius * cos); final float linePointX = centerX + (int) (lineLength * sin); final float linePointY = centerY - (int) (lineLength * cos); // Draw the line. - final Paint linePaint = mPaintSelector[index % 2][SELECTOR_LINE]; - linePaint.setColor(color); + final Paint linePaint = mPaintSelector[SELECTOR_LINE]; + linePaint.setColor(mSelectorColor); linePaint.setStrokeWidth(mSelectorStroke); canvas.drawLine(mXCenter, mYCenter, linePointX, linePointY, linePaint); } @@ -842,73 +871,6 @@ public class RadialTimePickerView extends View { } } - private static ObjectAnimator getFadeOutAnimator(IntHolder target, int startAlpha, int endAlpha, - InvalidateUpdateListener updateListener) { - final ObjectAnimator animator = ObjectAnimator.ofInt(target, "value", startAlpha, endAlpha); - animator.setDuration(FADE_OUT_DURATION); - animator.addUpdateListener(updateListener); - return animator; - } - - private static ObjectAnimator getFadeInAnimator(IntHolder target, int startAlpha, int endAlpha, - InvalidateUpdateListener updateListener) { - final float delayMultiplier = 0.25f; - final float transitionDurationMultiplier = 1f; - final float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier; - final int totalDuration = (int) (FADE_IN_DURATION * totalDurationMultiplier); - final float delayPoint = (delayMultiplier * FADE_IN_DURATION) / totalDuration; - - final Keyframe kf0, kf1, kf2; - kf0 = Keyframe.ofInt(0f, startAlpha); - kf1 = Keyframe.ofInt(delayPoint, startAlpha); - kf2 = Keyframe.ofInt(1f, endAlpha); - final PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("value", kf0, kf1, kf2); - - final ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, fadeIn); - animator.setDuration(totalDuration); - animator.addUpdateListener(updateListener); - return animator; - } - - private class InvalidateUpdateListener implements ValueAnimator.AnimatorUpdateListener { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - RadialTimePickerView.this.invalidate(); - } - } - - private void startHoursToMinutesAnimation() { - if (mHoursToMinutesAnims.size() == 0) { - mHoursToMinutesAnims.add(getFadeOutAnimator(mAlpha[HOURS], - ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); - mHoursToMinutesAnims.add(getFadeInAnimator(mAlpha[MINUTES], - ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener)); - } - - if (mTransition != null && mTransition.isRunning()) { - mTransition.end(); - } - mTransition = new AnimatorSet(); - mTransition.playTogether(mHoursToMinutesAnims); - mTransition.start(); - } - - private void startMinutesToHoursAnimation() { - if (mMinuteToHoursAnims.size() == 0) { - mMinuteToHoursAnims.add(getFadeOutAnimator(mAlpha[MINUTES], - ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); - mMinuteToHoursAnims.add(getFadeInAnimator(mAlpha[HOURS], - ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener)); - } - - if (mTransition != null && mTransition.isRunning()) { - mTransition.end(); - } - mTransition = new AnimatorSet(); - mTransition.playTogether(mMinuteToHoursAnims); - mTransition.start(); - } - private int getDegreesFromXY(float x, float y, boolean constrainOutside) { // Ensure the point is inside the touchable area. final int innerBound; @@ -992,6 +954,9 @@ public class RadialTimePickerView extends View { return false; } + // Ensure we're showing the correct picker. + animatePicker(mShowHours, ANIM_DURATION_TOUCH); + final int type; final int newValue; final boolean valueChanged; @@ -1356,20 +1321,4 @@ public class RadialTimePickerView extends View { return id >>> SHIFT_VALUE & MASK_VALUE; } } - - private static class IntHolder { - private int mValue; - - public IntHolder(int value) { - mValue = value; - } - - public void setValue(int value) { - mValue = value; - } - - public int getValue() { - return mValue; - } - } } diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 61ef6dc9d231..6d41c1d34058 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -200,8 +200,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl a.recycle(); - mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById( - R.id.radial_picker); + mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(R.id.radial_picker); + mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes); setupListeners(); diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index b6d736465e17..c9b81190ce38 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -2615,7 +2615,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (action == MotionEvent.ACTION_DOWN) { int y = (int)event.getY(); if (y >= (getHeight()-5) && !mWindow.hasChildren()) { - Log.i(TAG, "Watchiing!"); + Log.i(TAG, "Watching!"); mWatchingForMenu = true; } return false; diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java index 56cf9216d0c9..7b80ac261d73 100644 --- a/core/java/com/android/internal/widget/NonClientDecorView.java +++ b/core/java/com/android/internal/widget/NonClientDecorView.java @@ -17,15 +17,23 @@ package com.android.internal.widget; import android.content.Context; +import android.graphics.Color; import android.graphics.Rect; +import android.os.Looper; import android.os.RemoteException; import android.util.AttributeSet; +import android.view.Choreographer; +import android.view.DisplayListCanvas; import android.view.MotionEvent; +import android.view.RenderNode; +import android.view.ThreadedRenderer; import android.view.View; +import android.view.ViewRootImpl; import android.widget.LinearLayout; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.Window; +import android.view.WindowCallbacks; import android.util.Log; import android.util.TypedValue; @@ -58,7 +66,7 @@ import com.android.internal.policy.PhoneWindow; * This will be mitigated once b/22527834 will be addressed. */ public class NonClientDecorView extends LinearLayout - implements View.OnClickListener, View.OnTouchListener { + implements View.OnClickListener, View.OnTouchListener, WindowCallbacks { private final static String TAG = "NonClientDecorView"; // The height of a window which has focus in DIP. private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20; @@ -67,6 +75,8 @@ public class NonClientDecorView extends LinearLayout private PhoneWindow mOwner = null; private boolean mWindowHasShadow = false; private boolean mShowDecor = false; + // True when this object is listening for window size changes. + private boolean mAttachedCallbacksToRootViewImpl = false; // True if the window is being dragged. private boolean mDragging = false; @@ -85,6 +95,9 @@ public class NonClientDecorView extends LinearLayout // to max until the first layout command has been executed. private boolean mAllowUpdateElevation = false; + // The resize frame renderer. + private ResizeFrameThread mFrameRendererThread = null; + public NonClientDecorView(Context context) { super(context); } @@ -108,6 +121,18 @@ public class NonClientDecorView extends LinearLayout // By changing the outline provider to BOUNDS, the window can remove its // background without removing the shadow. mOwner.getDecorView().setOutlineProvider(ViewOutlineProvider.BOUNDS); + + if (!mAttachedCallbacksToRootViewImpl) { + // If there is no window callback installed there was no window set before. Set it now. + // Note that our ViewRootImpl object will not change. + getViewRootImpl().addWindowCallbacks(this); + mAttachedCallbacksToRootViewImpl = true; + } else if (mFrameRendererThread != null) { + // We are resizing and this call happened due to a configuration change. Tell the + // renderer about it. + mFrameRendererThread.onConfigurationChange(); + } + findViewById(R.id.maximize_window).setOnClickListener(this); findViewById(R.id.close_window).setOnClickListener(this); } @@ -251,7 +276,9 @@ public class NonClientDecorView extends LinearLayout **/ private void updateElevation() { float elevation = 0; - if (mWindowHasShadow) { + // Do not use a shadow when we are in resizing mode (mRenderer not null) since the shadow + // is bound to the content size and not the target size. + if (mWindowHasShadow && mFrameRendererThread == null) { boolean fill = isFillingScreen(); elevation = fill ? 0 : (mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : @@ -293,4 +320,274 @@ public class NonClientDecorView extends LinearLayout } } } + + @Override + public void onWindowDragResizeStart(Rect initialBounds) { + if (mOwner.isDestroyed()) { + // If the owner's window is gone, we should not be able to come here anymore. + releaseResources(); + return; + } + if (mFrameRendererThread != null) { + return; + } + final ThreadedRenderer renderer = + (ThreadedRenderer) mOwner.getDecorView().getHardwareRenderer(); + if (renderer != null) { + mFrameRendererThread = new ResizeFrameThread(renderer, initialBounds); + // 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 + // element which owns the caption and has the elevation. + updateElevation(); + } + } + + @Override + public void onWindowDragResizeEnd() { + releaseThreadedRenderer(); + } + + @Override + public void onWindowSizeIsChanging(Rect newBounds) { + if (mFrameRendererThread != null) { + mFrameRendererThread.setTargetRect(newBounds); + } + } + + /** + * Release the renderer thread which is usually done when the user stops resizing. + */ + private void releaseThreadedRenderer() { + if (mFrameRendererThread != null) { + mFrameRendererThread.releaseRenderer(); + mFrameRendererThread = null; + // Bring the shadow back. + updateElevation(); + } + } + + /** + * Called when the parent window is destroyed to release all resources. Note that this will also + * destroy the renderer thread. + */ + private void releaseResources() { + releaseThreadedRenderer(); + if (mAttachedCallbacksToRootViewImpl) { + ViewRootImpl.removeWindowCallbacks(this); + mAttachedCallbacksToRootViewImpl = false; + } + } + + /** + * The thread which draws the chrome while we are resizing. + * It starts with the creation and it ends once someone calls destroy(). + * Any size changes can be passed by a call to setTargetRect will passed to the thread and + * executed via the Choreographer. + */ + private class ResizeFrameThread extends Thread implements Choreographer.FrameCallback { + // This is containing the last requested size by a resize command. Note that this size might + // or might not have been applied to the output already. + private final Rect mTargetRect = new Rect(); + + // The render nodes for the multi threaded renderer. + private ThreadedRenderer mRenderer; + private RenderNode mFrameNode; + private RenderNode mBackdropNode; + + private final Rect mOldTargetRect = new Rect(); + private final Rect mNewTargetRect = new Rect(); + private Choreographer mChoreographer; + + // Cached size values from the last render for the case that the view hierarchy is gone + // during a configuration change. + private int mLastContentWidth; + private int mLastContentHeight; + private int mLastCaptionHeight; + private int mLastXOffset; + private int mLastYOffset; + + ResizeFrameThread(ThreadedRenderer renderer, Rect initialBounds) { + mRenderer = renderer; + + // Create the render nodes for our frame and backdrop which can be resized independently + // from the content. + mFrameNode = RenderNode.create("FrameNode", null); + mBackdropNode = RenderNode.create("BackdropNode", null); + + mRenderer.addRenderNode(mFrameNode, false); + mRenderer.addRenderNode(mBackdropNode, true); + + // Set the initial bounds and draw once so that we do not get a broken frame. + mTargetRect.set(initialBounds); + changeWindowSize(initialBounds); + + // Kick off our draw thread. + start(); + } + + /** + * Call this function asynchronously when the window size has been changed. The change will + * be picked up once per frame and the frame will be re-rendered accordingly. + * @param newTargetBounds The new target bounds. + */ + public void setTargetRect(Rect newTargetBounds) { + synchronized (this) { + mTargetRect.set(newTargetBounds); + // Notify of a bounds change. + pingRenderLocked(); + } + } + + /** + * The window got replaced due to a configuration change. + */ + public void onConfigurationChange() { + if (mRenderer != null) { + // Enforce a window redraw. + mOldTargetRect.set(0, 0, 0, 0); + pingRenderLocked(); + } + } + + /** + * All resources of the renderer will be released. This function can be called from the + * the UI thread as well as the renderer thread. + */ + public void releaseRenderer() { + synchronized (this) { + if (mRenderer != null) { + // Invalidate the current content bounds. + mRenderer.setContentDrawBounds(0, 0, 0, 0); + + // Remove the render nodes again (see comment above - better to do that only once). + mRenderer.removeRenderNode(mFrameNode); + mRenderer.removeRenderNode(mBackdropNode); + + mRenderer = null; + + // Exit the renderer loop. + pingRenderLocked(); + } + } + } + + @Override + public void run() { + try { + Looper.prepare(); + mChoreographer = Choreographer.getInstance(); + Looper.loop(); + } finally { + releaseRenderer(); + } + synchronized (this) { + // Make sure no more messages are being sent. + mChoreographer = null; + } + } + + /** + * The implementation of the FrameCallback. + * @param frameTimeNanos The time in nanoseconds when the frame started being rendered, + * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000} + */ + @Override + public void doFrame(long frameTimeNanos) { + if (mRenderer == null) { + // Tell the looper to stop. We are done. + Looper.myLooper().quit(); + return; + } + // Prevent someone from changing this while we are copying. + synchronized (this) { + mNewTargetRect.set(mTargetRect); + } + if (!mNewTargetRect.equals(mOldTargetRect)) { + mOldTargetRect.set(mNewTargetRect); + changeWindowSize(mNewTargetRect); + } + } + + /** + * Resizing the frame to fit the new window size. + * @param newBounds The window bounds which needs to be drawn. + */ + private void changeWindowSize(Rect newBounds) { + long startTime = System.currentTimeMillis(); + + // While a configuration change is taking place the view hierarchy might become + // inaccessible. For that case we remember the previous metrics to avoid flashes. + View caption = getChildAt(0); + View content = getChildAt(1); + if (caption != null && content != null) { + int captionHeight = caption.getHeight(); + int contentWidth = content.getWidth(); + int contentHeight = content.getHeight(); + // Get the draw position within our surface (shadow offsets). + int[] surfaceOrigin = new int[2]; + surfaceOrigin[0] = 0; + surfaceOrigin[1] = 0; + getLocationInSurface(surfaceOrigin); + // Only update if a layout has already be performed (which might not be after a + // relayout. Otherwise use the previous values for the content. + if (captionHeight != 0 && contentWidth != 0 && contentHeight != 0) { + mLastCaptionHeight = captionHeight; + mLastXOffset = surfaceOrigin[0]; + mLastYOffset = surfaceOrigin[1]; + mLastContentWidth = contentWidth; + mLastContentHeight = contentHeight; + } + } + + // Since the surface is spanning the entire screen, we have to add the start offset of + // the bounds to get to the surface location. + final int left = mLastXOffset + newBounds.left; + final int top = mLastYOffset + newBounds.top; + final int width = newBounds.width(); + final int height = newBounds.height(); + + // Produce the draw calls. + // TODO(skuhne): Create a separate caption view which draws this. If the shadow should + // be resized while the window resizes, this hierarchy needs to have the elevation. + // That said - it is probably no good idea to draw the shadow every time since it costs + // a considerable time which we should rather spend for resizing the content and it does + // barely show while the entire screen is moving. + mFrameNode.setLeftTopRightBottom(left, top, left + width, top + mLastCaptionHeight); + DisplayListCanvas canvas = mFrameNode.start(width, height); + canvas.drawColor(Color.BLACK); + mFrameNode.end(canvas); + + mBackdropNode.setLeftTopRightBottom(left, top + mLastCaptionHeight, left + width, + top + height); + + // The backdrop: clear everything with the background. Clipping is done elsewhere. + canvas = mBackdropNode.start(width, height - mLastCaptionHeight); + // TODO(skuhne): mOwner.getDecorView().mBackgroundFallback.draw(..) - or similar. + // Note: This might not work (calculator for example uses a transparent background). + canvas.drawColor(0xff808080); + mBackdropNode.end(canvas); + + // The current content buffer is drawn here. + mRenderer.setContentDrawBounds( + mLastXOffset, + mLastYOffset + mLastCaptionHeight, + mLastXOffset + mLastContentWidth, + mLastYOffset + mLastCaptionHeight + mLastContentHeight); + + // We need to render both rendered nodes explicitly. + mRenderer.drawRenderNode(mFrameNode); + mRenderer.drawRenderNode(mBackdropNode); + } + + /** + * Sends a message to the renderer to wake up and perform the next action which can be + * either the next rendering or the self destruction if mRenderer is null. + * Note: This call must be synchronized. + */ + private void pingRenderLocked() { + if (mChoreographer != null) { + mChoreographer.postFrameCallback(this); + } + } + } } diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 223dae0404c5..314e4b6f984e 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -66,10 +66,6 @@ static JMetricsID gFontMetrics_fieldID; static jclass gFontMetricsInt_class; static JMetricsID gFontMetricsInt_fieldID; -static jclass gPaint_class; -static jfieldID gPaint_nativeInstanceID; -static jfieldID gPaint_nativeTypefaceID; - static void defaultSettingsForAndroid(Paint* paint) { // GlyphID encoding is required because we are using Harfbuzz shaping paint->setTextEncoding(Paint::kGlyphID_TextEncoding); @@ -82,37 +78,17 @@ struct LocaleCacheEntry { static thread_local LocaleCacheEntry sSingleEntryLocaleCache; -class PaintGlue { -public: +namespace PaintGlue { enum MoveOpt { AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT }; - static Paint* getNativePaint(JNIEnv* env, jobject paint) { - SkASSERT(env); - SkASSERT(paint); - SkASSERT(env->IsInstanceOf(paint, gPaint_class)); - jlong paintHandle = env->GetLongField(paint, gPaint_nativeInstanceID); - android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle); - SkASSERT(p); - return p; - } - - static TypefaceImpl* getNativeTypeface(JNIEnv* env, jobject paint) { - SkASSERT(env); - SkASSERT(paint); - SkASSERT(env->IsInstanceOf(paint, gPaint_class)); - jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID); - android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle); - return p; - } - static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) { Paint* obj = reinterpret_cast<Paint*>(objHandle); delete obj; } - static jlong init(JNIEnv* env, jobject clazz) { + static jlong init(JNIEnv* env, jobject) { static_assert(1 << 0 == SkPaint::kAntiAlias_Flag, "paint_flags_mismatch"); static_assert(1 << 2 == SkPaint::kDither_Flag, "paint_flags_mismatch"); static_assert(1 << 3 == SkPaint::kUnderlineText_Flag, "paint_flags_mismatch"); @@ -149,9 +125,8 @@ public: // Equivalent to the Java Paint's FILTER_BITMAP_FLAG. static const uint32_t sFilterBitmapFlag = 0x02; - static jint getFlags(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - Paint* nativePaint = getNativePaint(env, paint); + static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) { + Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle); uint32_t result = nativePaint->getFlags(); result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away. if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) { @@ -160,9 +135,8 @@ public: return static_cast<jint>(result); } - static void setFlags(JNIEnv* env, jobject paint, jint flags) { - NPE_CHECK_RETURN_VOID(env, paint); - Paint* nativePaint = getNativePaint(env, paint); + static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) { + Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle); // Instead of modifying 0x02, change the filter level. nativePaint->setFilterQuality(flags & sFilterBitmapFlag ? kLow_SkFilterQuality @@ -175,57 +149,47 @@ public: nativePaint->setFlags(flags); } - static jint getHinting(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - return getNativePaint(env, paint)->getHinting() + static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) { + return reinterpret_cast<Paint*>(paintHandle)->getHinting() == Paint::kNo_Hinting ? 0 : 1; } - static void setHinting(JNIEnv* env, jobject paint, jint mode) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setHinting( + static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) { + reinterpret_cast<Paint*>(paintHandle)->setHinting( mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting); } - static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setAntiAlias(aa); + static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) { + reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa); } - static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setLinearText(linearText); + static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) { + reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText); } - static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setSubpixelText(subpixelText); + static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) { + reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText); } - static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setUnderlineText(underlineText); + static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) { + reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText); } - static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setStrikeThruText(strikeThruText); + static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) { + reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText); } - static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setFakeBoldText(fakeBoldText); + static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) { + reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText); } - static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setFilterQuality( + static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) { + reinterpret_cast<Paint*>(paintHandle)->setFilterQuality( filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality); } - static void setDither(JNIEnv* env, jobject paint, jboolean dither) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setDither(dither); + static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) { + reinterpret_cast<Paint*>(paintHandle)->setDither(dither); } static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) { @@ -239,48 +203,40 @@ public: obj->setStyle(style); } - static jint getColor(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); + static jint getColor(JNIEnv* env, jobject, jlong paintHandle) { int color; - color = getNativePaint(env, paint)->getColor(); + color = reinterpret_cast<Paint*>(paintHandle)->getColor(); return static_cast<jint>(color); } - static jint getAlpha(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); + static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) { int alpha; - alpha = getNativePaint(env, paint)->getAlpha(); + alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha(); return static_cast<jint>(alpha); } - static void setColor(JNIEnv* env, jobject paint, jint color) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setColor(color); + static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) { + reinterpret_cast<Paint*>(paintHandle)->setColor(color); } - static void setAlpha(JNIEnv* env, jobject paint, jint a) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setAlpha(a); + static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) { + reinterpret_cast<Paint*>(paintHandle)->setAlpha(a); } - static jfloat getStrokeWidth(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - return SkScalarToFloat(getNativePaint(env, paint)->getStrokeWidth()); + static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) { + return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth()); } - static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setStrokeWidth(width); + static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) { + reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width); } - static jfloat getStrokeMiter(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - return SkScalarToFloat(getNativePaint(env, paint)->getStrokeMiter()); + static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) { + return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter()); } - static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setStrokeMiter(miter); + static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) { + reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter); } static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) { @@ -417,46 +373,38 @@ public: obj->setTextLocale(sSingleEntryLocaleCache.languageTag); } - static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - Paint* obj = getNativePaint(env, paint); + static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) { + Paint* obj = reinterpret_cast<Paint*>(paintHandle); return obj->getFontVariant() == VARIANT_ELEGANT; } - static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) { - NPE_CHECK_RETURN_VOID(env, paint); - Paint* obj = getNativePaint(env, paint); + static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) { + Paint* obj = reinterpret_cast<Paint*>(paintHandle); obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT); } - static jfloat getTextSize(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - return SkScalarToFloat(getNativePaint(env, paint)->getTextSize()); + static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) { + return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize()); } - static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setTextSize(textSize); + static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) { + reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize); } - static jfloat getTextScaleX(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - return SkScalarToFloat(getNativePaint(env, paint)->getTextScaleX()); + static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) { + return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX()); } - static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setTextScaleX(scaleX); + static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) { + reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX); } - static jfloat getTextSkewX(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); - return SkScalarToFloat(getNativePaint(env, paint)->getTextSkewX()); + static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) { + return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX()); } - static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) { - NPE_CHECK_RETURN_VOID(env, paint); - getNativePaint(env, paint)->setTextSkewX(skewX); + static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) { + reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX); } static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) { @@ -489,14 +437,15 @@ public: paint->setHyphenEdit((uint32_t)hyphen); } - static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) { + static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle, + Paint::FontMetrics *metrics) { const int kElegantTop = 2500; const int kElegantBottom = -1000; const int kElegantAscent = 1900; const int kElegantDescent = -500; const int kElegantLeading = 0; - Paint* paint = getNativePaint(env, jpaint); - TypefaceImpl* typeface = getNativeTypeface(env, jpaint); + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); typeface = TypefaceImpl_resolveDefault(typeface); FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle); float saveSkewX = paint->getTextSkewX(); @@ -520,24 +469,22 @@ public: return spacing; } - static jfloat ascent(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); + static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) { Paint::FontMetrics metrics; - getMetricsInternal(env, paint, &metrics); + getMetricsInternal(paintHandle, typefaceHandle, &metrics); return SkScalarToFloat(metrics.fAscent); } - static jfloat descent(JNIEnv* env, jobject paint) { - NPE_CHECK_RETURN_ZERO(env, paint); + static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) { Paint::FontMetrics metrics; - getMetricsInternal(env, paint, &metrics); + getMetricsInternal(paintHandle, typefaceHandle, &metrics); return SkScalarToFloat(metrics.fDescent); } - static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) { - NPE_CHECK_RETURN_ZERO(env, paint); + static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, + jlong typefaceHandle, jobject metricsObj) { Paint::FontMetrics metrics; - SkScalar spacing = getMetricsInternal(env, paint, &metrics); + SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics); if (metricsObj) { SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class)); @@ -550,11 +497,11 @@ public: return SkScalarToFloat(spacing); } - static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) { - NPE_CHECK_RETURN_ZERO(env, paint); + static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, + jlong typefaceHandle, jobject metricsObj) { Paint::FontMetrics metrics; - getMetricsInternal(env, paint, &metrics); + getMetricsInternal(paintHandle, typefaceHandle, &metrics); int ascent = SkScalarRoundToInt(metrics.fAscent); int descent = SkScalarRoundToInt(metrics.fDescent); int leading = SkScalarRoundToInt(metrics.fLeading); @@ -573,7 +520,6 @@ public: static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags, jfloatArray advances, jint advancesIndex) { - NPE_CHECK_RETURN_ZERO(env, paint); NPE_CHECK_RETURN_ZERO(env, text); if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) { @@ -841,7 +787,7 @@ public: static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle, jstring text, jint start, jint end, jint bidiFlags, jobject bounds) { - const Paint* paint = reinterpret_cast<Paint*>(paintHandle);; + const Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); const jchar* textArray = env->GetStringChars(text, NULL); doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags); @@ -961,97 +907,97 @@ public: return result; } -}; +}; // namespace PaintGlue static const JNINativeMethod methods[] = { - {"finalizer", "(J)V", (void*) PaintGlue::finalizer}, - {"native_init","()J", (void*) PaintGlue::init}, - {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint}, - - {"native_reset","!(J)V", (void*) PaintGlue::reset}, - {"native_set","!(JJ)V", (void*) PaintGlue::assign}, - {"getFlags","!()I", (void*) PaintGlue::getFlags}, - {"setFlags","!(I)V", (void*) PaintGlue::setFlags}, - {"getHinting","!()I", (void*) PaintGlue::getHinting}, - {"setHinting","!(I)V", (void*) PaintGlue::setHinting}, - {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias}, - {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText}, - {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText}, - {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText}, - {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText}, - {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText}, - {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap}, - {"setDither","!(Z)V", (void*) PaintGlue::setDither}, - {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle}, - {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle}, - {"getColor","!()I", (void*) PaintGlue::getColor}, - {"setColor","!(I)V", (void*) PaintGlue::setColor}, - {"getAlpha","!()I", (void*) PaintGlue::getAlpha}, - {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha}, - {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth}, - {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth}, - {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter}, - {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter}, - {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap}, - {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap}, - {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin}, - {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin}, - {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath}, - {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader}, - {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter}, - {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode}, - {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect}, - {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter}, - {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface}, - {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, - {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, - {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, - {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale}, - {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight}, - {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight}, - {"getTextSize","!()F", (void*) PaintGlue::getTextSize}, - {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize}, - {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX}, - {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX}, - {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX}, - {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX}, - {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing}, - {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing}, - {"native_setFontFeatureSettings","(JLjava/lang/String;)V", + {"nFinalizer", "(J)V", (void*) PaintGlue::finalizer}, + {"nInit","()J", (void*) PaintGlue::init}, + {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint}, + + {"nReset","!(J)V", (void*) PaintGlue::reset}, + {"nSet","!(JJ)V", (void*) PaintGlue::assign}, + {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags}, + {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags}, + {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting}, + {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting}, + {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias}, + {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText}, + {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText}, + {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText}, + {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText}, + {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText}, + {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap}, + {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither}, + {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle}, + {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle}, + {"nGetColor","!(J)I", (void*) PaintGlue::getColor}, + {"nSetColor","!(JI)V", (void*) PaintGlue::setColor}, + {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha}, + {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha}, + {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth}, + {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth}, + {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter}, + {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter}, + {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap}, + {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap}, + {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin}, + {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin}, + {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath}, + {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader}, + {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter}, + {"nSetXfermode","!(JJ)J", (void*) PaintGlue::setXfermode}, + {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect}, + {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter}, + {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface}, + {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, + {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, + {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, + {"nSetTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale}, + {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight}, + {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight}, + {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize}, + {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize}, + {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX}, + {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX}, + {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX}, + {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX}, + {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing}, + {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing}, + {"nSetFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, - {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit}, - {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit}, - {"ascent","!()F", (void*) PaintGlue::ascent}, - {"descent","!()F", (void*) PaintGlue::descent}, + {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit}, + {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit}, + {"nAscent","!(JJ)F", (void*) PaintGlue::ascent}, + {"nDescent","!(JJ)F", (void*) PaintGlue::descent}, - {"getFontMetrics", "!(Landroid/graphics/Paint$FontMetrics;)F", + {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, - {"getFontMetricsInt", "!(Landroid/graphics/Paint$FontMetricsInt;)I", + {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, - {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC}, - {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS}, - {"native_getTextAdvances","(JJ[CIIIII[FI)F", + {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC}, + {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS}, + {"nGetTextAdvances","(JJ[CIIIII[FI)F", (void*) PaintGlue::getTextAdvances___CIIIII_FI}, - {"native_getTextAdvances","(JJLjava/lang/String;IIIII[FI)F", + {"nGetTextAdvances","(JJLjava/lang/String;IIIII[FI)F", (void*) PaintGlue::getTextAdvances__StringIIIII_FI}, - {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C}, - {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I", + {"nGetTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C}, + {"nGetTextRunCursor", "(JLjava/lang/String;IIIII)I", (void*) PaintGlue::getTextRunCursor__String}, - {"native_getTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C}, - {"native_getTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String}, - {"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V", + {"nGetTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C}, + {"nGetTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String}, + {"nGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V", (void*) PaintGlue::getStringBounds }, - {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V", + {"nGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V", (void*) PaintGlue::getCharArrayBounds }, - {"native_hasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph }, - {"native_getRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F}, - {"native_getOffsetForAdvance", "(JJ[CIIIIZF)I", + {"nHasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph }, + {"nGetRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F}, + {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I", (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I}, - {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer}, - {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer} + {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer}, + {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer} }; int register_android_graphics_Paint(JNIEnv* env) { @@ -1073,10 +1019,6 @@ int register_android_graphics_Paint(JNIEnv* env) { gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I"); gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I"); - gPaint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Paint")); - gPaint_nativeInstanceID = GetFieldIDOrDie(env, gPaint_class, "mNativePaint", "J"); - gPaint_nativeTypefaceID = GetFieldIDOrDie(env, gPaint_class, "mNativeTypeface", "J"); - return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods)); } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index c79f833b54a9..17eb876aebf3 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -461,10 +461,10 @@ static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject c proxy->drawRenderNode(renderNode); } -static void android_view_ThreadedRenderer_setContentOverdrawProtectionBounds(JNIEnv* env, +static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env, jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->setContentOverdrawProtectionBounds(left, top, right, bottom); + proxy->setContentDrawBounds(left, top, right, bottom); } // ---------------------------------------------------------------------------- @@ -522,8 +522,7 @@ static const JNINativeMethod gMethods[] = { { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode}, { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode}, { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode}, - { "nSetContentOverdrawProtectionBounds", "(JIIII)V", - (void*)android_view_ThreadedRenderer_setContentOverdrawProtectionBounds}, + { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds}, }; int register_android_view_ThreadedRenderer(JNIEnv* env) { diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 38a1693141dc..58640eb2ef55 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -307,9 +307,10 @@ please see styles_device_defaults.xml. <style name="TextAppearance.Material.Widget.PopupMenu"/> <style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" /> <style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" /> - <style name="TextAppearance.Material.Widget.PopupMenu.Header" parent="TextAppearance.Material.Subhead"> + <style name="TextAppearance.Material.Widget.PopupMenu.Header"> <item name="fontFamily">@string/font_family_title_material</item> <item name="textSize">@dimen/text_size_menu_header_material</item> + <item name="textColor">?attr/textColorSecondary</item> </style> <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" /> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 58de87af1a5d..11b4a9e5adf5 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -430,7 +430,7 @@ public class Paint { * @param flags initial flag bits, as if they were passed via setFlags(). */ public Paint(int flags) { - mNativePaint = native_init(); + mNativePaint = nInit(); setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS); // TODO: Turning off hinting has undesirable side effects, we need to // revisit hinting once we add support for subpixel positioning @@ -448,13 +448,14 @@ public class Paint { * new paint. */ public Paint(Paint paint) { - mNativePaint = native_initWithPaint(paint.getNativeInstance()); + mNativePaint = nInitWithPaint(paint.getNativeInstance()); setClassVariablesFrom(paint); } /** Restores the paint to its default settings. */ public void reset() { - native_reset(mNativePaint); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nReset(mNativePaint); setFlags(HIDDEN_DEFAULT_PAINT_FLAGS); // TODO: Turning off hinting has undesirable side effects, we need to @@ -488,9 +489,11 @@ public class Paint { * methods on this. */ public void set(Paint src) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + if (src.mNativePaint == 0) throw new NullPointerException("Source is already finalized!"); if (this != src) { // copy over the native settings - native_set(mNativePaint, src.mNativePaint); + nSet(mNativePaint, src.mNativePaint); setClassVariablesFrom(src); } } @@ -538,10 +541,11 @@ public class Paint { * @hide */ public long getNativeInstance() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance(); if (newNativeShader != mNativeShader) { mNativeShader = newNativeShader; - native_setShader(mNativePaint, mNativeShader); + nSetShader(mNativePaint, mNativeShader); } return mNativePaint; } @@ -574,26 +578,46 @@ public class Paint { * * @return the paint's flags (see enums ending in _Flag for bit masks) */ - public native int getFlags(); + public int getFlags() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetFlags(mNativePaint); + } + + private native int nGetFlags(long paintPtr); /** * Set the paint's flags. Use the Flag enum to specific flag values. * * @param flags The new flag bits for the paint */ - public native void setFlags(int flags); + public void setFlags(int flags) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetFlags(mNativePaint, flags); + } + + private native void nSetFlags(long paintPtr, int flags); /** * Return the paint's hinting mode. Returns either * {@link #HINTING_OFF} or {@link #HINTING_ON}. */ - public native int getHinting(); + public int getHinting() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetHinting(mNativePaint); + } + + private native int nGetHinting(long paintPtr); /** * Set the paint's hinting mode. May be either * {@link #HINTING_OFF} or {@link #HINTING_ON}. */ - public native void setHinting(int mode); + public void setHinting(int mode) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetHinting(mNativePaint, mode); + } + + private native void nSetHinting(long paintPtr, int mode); /** * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set @@ -615,7 +639,12 @@ public class Paint { * * @param aa true to set the antialias bit in the flags, false to clear it */ - public native void setAntiAlias(boolean aa); + public void setAntiAlias(boolean aa) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetAntiAlias(mNativePaint, aa); + } + + private native void nSetAntiAlias(long paintPtr, boolean aa); /** * Helper for getFlags(), returning true if DITHER_FLAG bit is set @@ -641,7 +670,12 @@ public class Paint { * * @param dither true to set the dithering bit in flags, false to clear it */ - public native void setDither(boolean dither); + public void setDither(boolean dither) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetDither(mNativePaint, dither); + } + + private native void nSetDither(long paintPtr, boolean dither); /** * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set @@ -658,7 +692,12 @@ public class Paint { * @param linearText true to set the linearText bit in the paint's flags, * false to clear it. */ - public native void setLinearText(boolean linearText); + public void setLinearText(boolean linearText) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetLinearText(mNativePaint, linearText); + } + + private native void nSetLinearText(long paintPtr, boolean linearText); /** * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set @@ -675,7 +714,12 @@ public class Paint { * @param subpixelText true to set the subpixelText bit in the paint's * flags, false to clear it. */ - public native void setSubpixelText(boolean subpixelText); + public void setSubpixelText(boolean subpixelText) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetSubpixelText(mNativePaint, subpixelText); + } + + private native void nSetSubpixelText(long paintPtr, boolean subpixelText); /** * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set @@ -692,7 +736,12 @@ public class Paint { * @param underlineText true to set the underlineText bit in the paint's * flags, false to clear it. */ - public native void setUnderlineText(boolean underlineText); + public void setUnderlineText(boolean underlineText) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetUnderlineText(mNativePaint, underlineText); + } + + private native void nSetUnderlineText(long paintPtr, boolean underlineText); /** * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set @@ -709,7 +758,12 @@ public class Paint { * @param strikeThruText true to set the strikeThruText bit in the paint's * flags, false to clear it. */ - public native void setStrikeThruText(boolean strikeThruText); + public void setStrikeThruText(boolean strikeThruText) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetStrikeThruText(mNativePaint, strikeThruText); + } + + private native void nSetStrikeThruText(long paintPtr, boolean strikeThruText); /** * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set @@ -726,7 +780,12 @@ public class Paint { * @param fakeBoldText true to set the fakeBoldText bit in the paint's * flags, false to clear it. */ - public native void setFakeBoldText(boolean fakeBoldText); + public void setFakeBoldText(boolean fakeBoldText) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetFakeBoldText(mNativePaint, fakeBoldText); + } + + private native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText); /** * Whether or not the bitmap filter is activated. @@ -749,7 +808,12 @@ public class Paint { * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's * flags, false to clear it. */ - public native void setFilterBitmap(boolean filter); + public void setFilterBitmap(boolean filter) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetFilterBitmap(mNativePaint, filter); + } + + private native void nSetFilterBitmap(long paintPtr, boolean filter); /** * Return the paint's style, used for controlling how primitives' @@ -759,7 +823,8 @@ public class Paint { * @return the paint's style setting (Fill, Stroke, StrokeAndFill) */ public Style getStyle() { - return sStyleArray[native_getStyle(mNativePaint)]; + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return sStyleArray[nGetStyle(mNativePaint)]; } /** @@ -770,7 +835,8 @@ public class Paint { * @param style The new style to set in the paint */ public void setStyle(Style style) { - native_setStyle(mNativePaint, style.nativeInt); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetStyle(mNativePaint, style.nativeInt); } /** @@ -782,7 +848,12 @@ public class Paint { * @return the paint's color (and alpha). */ @ColorInt - public native int getColor(); + public int getColor() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetColor(mNativePaint); + } + + private native int nGetColor(long paintPtr); /** * Set the paint's color. Note that the color is an int containing alpha @@ -792,7 +863,12 @@ public class Paint { * * @param color The new color (including alpha) to set in the paint. */ - public native void setColor(@ColorInt int color); + public void setColor(@ColorInt int color) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetColor(mNativePaint, color); + } + + private native void nSetColor(long paintPtr, @ColorInt int color); /** * Helper to getColor() that just returns the color's alpha value. This is @@ -801,7 +877,12 @@ public class Paint { * * @return the alpha component of the paint's color. */ - public native int getAlpha(); + public int getAlpha() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetAlpha(mNativePaint); + } + + private native int nGetAlpha(long paintPtr); /** * Helper to setColor(), that only assigns the color's alpha value, @@ -810,7 +891,12 @@ public class Paint { * * @param a set the alpha component [0..255] of the paint's color. */ - public native void setAlpha(int a); + public void setAlpha(int a) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetAlpha(mNativePaint, a); + } + + private native void nSetAlpha(long paintPtr, int a); /** * Helper to setColor(), that takes a,r,g,b and constructs the color int @@ -833,7 +919,12 @@ public class Paint { * @return the paint's stroke width, used whenever the paint's style is * Stroke or StrokeAndFill. */ - public native float getStrokeWidth(); + public float getStrokeWidth() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetStrokeWidth(mNativePaint); + } + + private native float nGetStrokeWidth(long paintPtr); /** * Set the width for stroking. @@ -843,7 +934,12 @@ public class Paint { * @param width set the paint's stroke width, used whenever the paint's * style is Stroke or StrokeAndFill. */ - public native void setStrokeWidth(float width); + public void setStrokeWidth(float width) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetStrokeWidth(mNativePaint, width); + } + + private native void nSetStrokeWidth(long paintPtr, float width); /** * Return the paint's stroke miter value. Used to control the behavior @@ -852,7 +948,12 @@ public class Paint { * @return the paint's miter limit, used whenever the paint's style is * Stroke or StrokeAndFill. */ - public native float getStrokeMiter(); + public float getStrokeMiter() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetStrokeMiter(mNativePaint); + } + + private native float nGetStrokeMiter(long paintPtr); /** * Set the paint's stroke miter value. This is used to control the behavior @@ -861,7 +962,12 @@ public class Paint { * @param miter set the miter limit on the paint, used whenever the paint's * style is Stroke or StrokeAndFill. */ - public native void setStrokeMiter(float miter); + public void setStrokeMiter(float miter) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetStrokeMiter(mNativePaint, miter); + } + + private native void nSetStrokeMiter(long paintPtr, float miter); /** * Return the paint's Cap, controlling how the start and end of stroked @@ -871,7 +977,8 @@ public class Paint { * style is Stroke or StrokeAndFill. */ public Cap getStrokeCap() { - return sCapArray[native_getStrokeCap(mNativePaint)]; + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return sCapArray[nGetStrokeCap(mNativePaint)]; } /** @@ -881,7 +988,8 @@ public class Paint { * style is Stroke or StrokeAndFill. */ public void setStrokeCap(Cap cap) { - native_setStrokeCap(mNativePaint, cap.nativeInt); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetStrokeCap(mNativePaint, cap.nativeInt); } /** @@ -890,7 +998,8 @@ public class Paint { * @return the paint's Join. */ public Join getStrokeJoin() { - return sJoinArray[native_getStrokeJoin(mNativePaint)]; + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return sJoinArray[nGetStrokeJoin(mNativePaint)]; } /** @@ -900,7 +1009,8 @@ public class Paint { * Stroke or StrokeAndFill. */ public void setStrokeJoin(Join join) { - native_setStrokeJoin(mNativePaint, join.nativeInt); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetStrokeJoin(mNativePaint, join.nativeInt); } /** @@ -915,7 +1025,8 @@ public class Paint { * drawn with a hairline (width == 0) */ public boolean getFillPath(Path src, Path dst) { - return native_getFillPath(mNativePaint, src.ni(), dst.ni()); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetFillPath(mNativePaint, src.ni(), dst.ni()); } /** @@ -958,10 +1069,11 @@ public class Paint { * @return filter */ public ColorFilter setColorFilter(ColorFilter filter) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long filterNative = 0; if (filter != null) filterNative = filter.native_instance; - native_setColorFilter(mNativePaint, filterNative); + nSetColorFilter(mNativePaint, filterNative); mColorFilter = filter; return filter; } @@ -985,10 +1097,11 @@ public class Paint { * @return xfermode */ public Xfermode setXfermode(Xfermode xfermode) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long xfermodeNative = 0; if (xfermode != null) xfermodeNative = xfermode.native_instance; - native_setXfermode(mNativePaint, xfermodeNative); + nSetXfermode(mNativePaint, xfermodeNative); mXfermode = xfermode; return xfermode; } @@ -1012,11 +1125,12 @@ public class Paint { * @return effect */ public PathEffect setPathEffect(PathEffect effect) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long effectNative = 0; if (effect != null) { effectNative = effect.native_instance; } - native_setPathEffect(mNativePaint, effectNative); + nSetPathEffect(mNativePaint, effectNative); mPathEffect = effect; return effect; } @@ -1041,11 +1155,12 @@ public class Paint { * @return maskfilter */ public MaskFilter setMaskFilter(MaskFilter maskfilter) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long maskfilterNative = 0; if (maskfilter != null) { maskfilterNative = maskfilter.native_instance; } - native_setMaskFilter(mNativePaint, maskfilterNative); + nSetMaskFilter(mNativePaint, maskfilterNative); mMaskFilter = maskfilter; return maskfilter; } @@ -1072,11 +1187,12 @@ public class Paint { * @return typeface */ public Typeface setTypeface(Typeface typeface) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long typefaceNative = 0; if (typeface != null) { typefaceNative = typeface.native_instance; } - native_setTypeface(mNativePaint, typefaceNative); + nSetTypeface(mNativePaint, typefaceNative); mTypeface = typeface; mNativeTypeface = typefaceNative; return typeface; @@ -1110,11 +1226,12 @@ public class Paint { */ @Deprecated public Rasterizer setRasterizer(Rasterizer rasterizer) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); long rasterizerNative = 0; if (rasterizer != null) { rasterizerNative = rasterizer.native_instance; } - native_setRasterizer(mNativePaint, rasterizerNative); + nSetRasterizer(mNativePaint, rasterizerNative); mRasterizer = rasterizer; return rasterizer; } @@ -1132,7 +1249,8 @@ public class Paint { * opaque, or the alpha from the shadow color if not. */ public void setShadowLayer(float radius, float dx, float dy, int shadowColor) { - native_setShadowLayer(mNativePaint, radius, dx, dy, shadowColor); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor); } /** @@ -1149,7 +1267,8 @@ public class Paint { * @hide */ public boolean hasShadowLayer() { - return native_hasShadowLayer(mNativePaint); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nHasShadowLayer(mNativePaint); } /** @@ -1161,7 +1280,8 @@ public class Paint { * @return the paint's Align value for drawing text. */ public Align getTextAlign() { - return sAlignArray[native_getTextAlign(mNativePaint)]; + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return sAlignArray[nGetTextAlign(mNativePaint)]; } /** @@ -1173,7 +1293,8 @@ public class Paint { * @param align set the paint's Align value for drawing text. */ public void setTextAlign(Align align) { - native_setTextAlign(mNativePaint, align.nativeInt); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetTextAlign(mNativePaint, align.nativeInt); } /** @@ -1206,6 +1327,7 @@ public class Paint { * @param locale the paint's locale value for drawing text, must not be null. */ public void setTextLocale(@NonNull Locale locale) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (locale == null) { throw new IllegalArgumentException("locale cannot be null"); } @@ -1213,7 +1335,7 @@ public class Paint { return; } mLocales = new LocaleList(locale); - native_setTextLocale(mNativePaint, locale.toString()); + nSetTextLocale(mNativePaint, locale.toString()); } /** @@ -1244,13 +1366,14 @@ public class Paint { * @param locales the paint's locale list for drawing text, must not be null or empty. */ public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (locales == null || locales.isEmpty()) { throw new IllegalArgumentException("locales cannot be null or empty"); } if (locales.equals(mLocales)) return; mLocales = locales; // TODO: Pass the whole LocaleList to native code - native_setTextLocale(mNativePaint, locales.getPrimary().toString()); + nSetTextLocale(mNativePaint, locales.getPrimary().toString()); } /** @@ -1258,7 +1381,12 @@ public class Paint { * * @return true if elegant metrics are enabled for text drawing. */ - public native boolean isElegantTextHeight(); + public boolean isElegantTextHeight() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nIsElegantTextHeight(mNativePaint); + } + + private native boolean nIsElegantTextHeight(long paintPtr); /** * Set the paint's elegant height metrics flag. This setting selects font @@ -1267,21 +1395,36 @@ public class Paint { * * @param elegant set the paint's elegant metrics flag for drawing text. */ - public native void setElegantTextHeight(boolean elegant); + public void setElegantTextHeight(boolean elegant) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetElegantTextHeight(mNativePaint, elegant); + } + + private native void nSetElegantTextHeight(long paintPtr, boolean elegant); /** * Return the paint's text size. * * @return the paint's text size. */ - public native float getTextSize(); + public float getTextSize() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetTextSize(mNativePaint); + } + + private native float nGetTextSize(long paintPtr); /** * Set the paint's text size. This value must be > 0 * * @param textSize set the paint's text size. */ - public native void setTextSize(float textSize); + public void setTextSize(float textSize) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetTextSize(mNativePaint, textSize); + } + + private native void nSetTextSize(long paintPtr, float textSize); /** * Return the paint's horizontal scale factor for text. The default value @@ -1289,7 +1432,12 @@ public class Paint { * * @return the paint's scale factor in X for drawing/measuring text */ - public native float getTextScaleX(); + public float getTextScaleX() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetTextScaleX(mNativePaint); + } + + private native float nGetTextScaleX(long paintPtr); /** * Set the paint's horizontal scale factor for text. The default value @@ -1298,7 +1446,12 @@ public class Paint { * * @param scaleX set the paint's scale in X for drawing/measuring text. */ - public native void setTextScaleX(float scaleX); + public void setTextScaleX(float scaleX) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetTextScaleX(mNativePaint, scaleX); + } + + private native void nSetTextScaleX(long paintPtr, float scaleX); /** * Return the paint's horizontal skew factor for text. The default value @@ -1306,7 +1459,12 @@ public class Paint { * * @return the paint's skew factor in X for drawing text. */ - public native float getTextSkewX(); + public float getTextSkewX() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetTextSkewX(mNativePaint); + } + + private native float nGetTextSkewX(long paintPtr); /** * Set the paint's horizontal skew factor for text. The default value @@ -1314,7 +1472,12 @@ public class Paint { * * @param skewX set the paint's skew factor in X for drawing text. */ - public native void setTextSkewX(float skewX); + public void setTextSkewX(float skewX) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetTextSkewX(mNativePaint, skewX); + } + + private native void nSetTextSkewX(long paintPtr, float skewX); /** * Return the paint's letter-spacing for text. The default value @@ -1323,7 +1486,8 @@ public class Paint { * @return the paint's letter-spacing for drawing text. */ public float getLetterSpacing() { - return native_getLetterSpacing(mNativePaint); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetLetterSpacing(mNativePaint); } /** @@ -1334,7 +1498,8 @@ public class Paint { * @param letterSpacing set the paint's letter-spacing for drawing text. */ public void setLetterSpacing(float letterSpacing) { - native_setLetterSpacing(mNativePaint, letterSpacing); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetLetterSpacing(mNativePaint, letterSpacing); } /** @@ -1355,6 +1520,7 @@ public class Paint { * @param settings the font feature settings string to use, may be null. */ public void setFontFeatureSettings(String settings) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (settings != null && settings.equals("")) { settings = null; } @@ -1363,7 +1529,7 @@ public class Paint { return; } mFontFeatureSettings = settings; - native_setFontFeatureSettings(mNativePaint, settings); + nSetFontFeatureSettings(mNativePaint, settings); } /** @@ -1374,7 +1540,8 @@ public class Paint { * @hide */ public int getHyphenEdit() { - return native_getHyphenEdit(mNativePaint); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetHyphenEdit(mNativePaint); } /** @@ -1386,7 +1553,8 @@ public class Paint { * @hide */ public void setHyphenEdit(int hyphen) { - native_setHyphenEdit(mNativePaint, hyphen); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + nSetHyphenEdit(mNativePaint, hyphen); } /** @@ -1396,7 +1564,12 @@ public class Paint { * @return the distance above (negative) the baseline (ascent) based on the * current typeface and text size. */ - public native float ascent(); + public float ascent() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nAscent(mNativePaint, mNativeTypeface); + } + + private native float nAscent(long paintPtr, long typefacePtr); /** * Return the distance below (positive) the baseline (descent) based on the @@ -1405,7 +1578,12 @@ public class Paint { * @return the distance below (positive) the baseline (descent) based on * the current typeface and text size. */ - public native float descent(); + public float descent() { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nDescent(mNativePaint, mNativeTypeface); + } + + private native float nDescent(long paintPtr, long typefacePtr); /** * Class that describes the various metrics for a font at a given text size. @@ -1447,7 +1625,13 @@ public class Paint { * the appropriate values given the paint's text attributes. * @return the font's recommended interline spacing. */ - public native float getFontMetrics(FontMetrics metrics); + public float getFontMetrics(FontMetrics metrics) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics); + } + + private native float nGetFontMetrics(long paintPtr, + long typefacePtr, FontMetrics metrics); /** * Allocates a new FontMetrics object, and then calls getFontMetrics(fm) @@ -1487,7 +1671,13 @@ public class Paint { * * @return the font's interline spacing. */ - public native int getFontMetricsInt(FontMetricsInt fmi); + public int getFontMetricsInt(FontMetricsInt fmi) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi); + } + + private native int nGetFontMetricsInt(long paintPtr, + long typefacePtr, FontMetricsInt fmi); public FontMetricsInt getFontMetricsInt() { FontMetricsInt fm = new FontMetricsInt(); @@ -1515,6 +1705,7 @@ public class Paint { * @return The width of the text */ public float measureText(char[] text, int index, int count) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1526,13 +1717,13 @@ public class Paint { return 0f; } if (!mHasCompatScaling) { - return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text, + return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, mBidiFlags, null, 0)); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, + float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, mBidiFlags, null, 0); setTextSize(oldSize); return (float) Math.ceil(w*mInvCompatScaling); @@ -1547,6 +1738,7 @@ public class Paint { * @return The width of the text */ public float measureText(String text, int start, int end) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1558,12 +1750,12 @@ public class Paint { return 0f; } if (!mHasCompatScaling) { - return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text, + return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, mBidiFlags, null, 0)); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, + float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, mBidiFlags, null, 0); setTextSize(oldSize); return (float) Math.ceil(w * mInvCompatScaling); @@ -1576,6 +1768,7 @@ public class Paint { * @return The width of the text */ public float measureText(String text) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1636,6 +1829,7 @@ public class Paint { */ public int breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1647,20 +1841,20 @@ public class Paint { return 0; } if (!mHasCompatScaling) { - return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth, + return nBreakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth, mBidiFlags, measuredWidth); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count, + int res = nBreakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth * mCompatScaling, mBidiFlags, measuredWidth); setTextSize(oldSize); if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling; return res; } - private static native int native_breakText(long native_object, long native_typeface, + private static native int nBreakText(long nObject, long nTypeface, char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth); @@ -1683,6 +1877,7 @@ public class Paint { public int breakText(CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1731,6 +1926,7 @@ public class Paint { */ public int breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1739,20 +1935,20 @@ public class Paint { return 0; } if (!mHasCompatScaling) { - return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards, + return nBreakText(mNativePaint, mNativeTypeface, text, measureForwards, maxWidth, mBidiFlags, measuredWidth); } final float oldSize = getTextSize(); setTextSize(oldSize*mCompatScaling); - int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards, + int res = nBreakText(mNativePaint, mNativeTypeface, text, measureForwards, maxWidth*mCompatScaling, mBidiFlags, measuredWidth); setTextSize(oldSize); if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling; return res; } - private static native int native_breakText(long native_object, long native_typeface, + private static native int nBreakText(long nObject, long nTypeface, String text, boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth); @@ -1768,6 +1964,7 @@ public class Paint { */ public int getTextWidths(char[] text, int index, int count, float[] widths) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1780,14 +1977,14 @@ public class Paint { return 0; } if (!mHasCompatScaling) { - native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, + nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, mBidiFlags, widths, 0); return count; } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, + nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, mBidiFlags, widths, 0); setTextSize(oldSize); for (int i = 0; i < count; i++) { @@ -1851,6 +2048,7 @@ public class Paint { * @return the number of code units in the specified text. */ public int getTextWidths(String text, int start, int end, float[] widths) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1865,14 +2063,14 @@ public class Paint { return 0; } if (!mHasCompatScaling) { - native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, + nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, mBidiFlags, widths, 0); return end - start; } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, + nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, mBidiFlags, widths, 0); setTextSize(oldSize); for (int i = 0; i < end - start; i++) { @@ -1904,6 +2102,7 @@ public class Paint { int contextIndex, int contextCount, boolean isRtl, float[] advances, int advancesIndex) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (chars == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -1920,14 +2119,14 @@ public class Paint { return 0f; } if (!mHasCompatScaling) { - return native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, + return nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - float res = native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, + float res = nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex); setTextSize(oldSize); @@ -1950,7 +2149,7 @@ public class Paint { public float getTextRunAdvances(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex) { - + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2032,6 +2231,7 @@ public class Paint { */ public float getTextRunAdvances(String text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2048,14 +2248,14 @@ public class Paint { } if (!mHasCompatScaling) { - return native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, + return nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - float totalAdvance = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, + float totalAdvance = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex); setTextSize(oldSize); @@ -2096,6 +2296,7 @@ public class Paint { */ public int getTextRunCursor(char[] text, int contextStart, int contextLength, int dir, int offset, int cursorOpt) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); int contextEnd = contextStart + contextLength; if (((contextStart | contextEnd | offset | (contextEnd - contextStart) | (offset - contextStart) | (contextEnd - offset) @@ -2104,7 +2305,7 @@ public class Paint { throw new IndexOutOfBoundsException(); } - return native_getTextRunCursor(mNativePaint, text, + return nGetTextRunCursor(mNativePaint, text, contextStart, contextLength, dir, offset, cursorOpt); } @@ -2183,6 +2384,7 @@ public class Paint { */ public int getTextRunCursor(String text, int contextStart, int contextEnd, int dir, int offset, int cursorOpt) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (((contextStart | contextEnd | offset | (contextEnd - contextStart) | (offset - contextStart) | (contextEnd - offset) | (text.length() - contextEnd) | cursorOpt) < 0) @@ -2190,7 +2392,7 @@ public class Paint { throw new IndexOutOfBoundsException(); } - return native_getTextRunCursor(mNativePaint, text, + return nGetTextRunCursor(mNativePaint, text, contextStart, contextEnd, dir, offset, cursorOpt); } @@ -2209,10 +2411,11 @@ public class Paint { */ public void getTextPath(char[] text, int index, int count, float x, float y, Path path) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if ((index | count) < 0 || index + count > text.length) { throw new ArrayIndexOutOfBoundsException(); } - native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y, + nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y, path.ni()); } @@ -2231,10 +2434,11 @@ public class Paint { */ public void getTextPath(String text, int start, int end, float x, float y, Path path) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if ((start | end | (end - start) | (text.length() - end)) < 0) { throw new IndexOutOfBoundsException(); } - native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y, + nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y, path.ni()); } @@ -2249,13 +2453,14 @@ public class Paint { * allocated by the caller. */ public void getTextBounds(String text, int start, int end, Rect bounds) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if ((start | end | (end - start) | (text.length() - end)) < 0) { throw new IndexOutOfBoundsException(); } if (bounds == null) { throw new NullPointerException("need bounds Rect"); } - nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds); + nGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds); } /** @@ -2269,13 +2474,14 @@ public class Paint { * allocated by the caller. */ public void getTextBounds(char[] text, int index, int count, Rect bounds) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if ((index | count) < 0 || index + count > text.length) { throw new ArrayIndexOutOfBoundsException(); } if (bounds == null) { throw new NullPointerException("need bounds Rect"); } - nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, + nGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, bounds); } @@ -2296,7 +2502,8 @@ public class Paint { * @return true if the typeface has a glyph for the string */ public boolean hasGlyph(String string) { - return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string); + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); + return nHasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string); } /** @@ -2337,6 +2544,7 @@ public class Paint { */ public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2349,7 +2557,7 @@ public class Paint { return 0.0f; } // TODO: take mCompatScaling into account (or eliminate compat scaling)? - return native_getRunAdvance(mNativePaint, mNativeTypeface, text, start, end, + return nGetRunAdvance(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl, offset); } @@ -2367,6 +2575,7 @@ public class Paint { */ public float getRunAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2417,6 +2626,7 @@ public class Paint { */ public int getOffsetForAdvance(char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2426,7 +2636,7 @@ public class Paint { throw new IndexOutOfBoundsException(); } // TODO: take mCompatScaling into account (or eliminate compat scaling)? - return native_getOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end, + return nGetOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end, contextStart, contextEnd, isRtl, advance); } @@ -2444,6 +2654,7 @@ public class Paint { */ public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance) { + if (mNativePaint == 0) throw new NullPointerException("Already finalized!"); if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2464,90 +2675,88 @@ public class Paint { @Override protected void finalize() throws Throwable { try { - finalizer(mNativePaint); - mNativePaint = 0; + if (mNativePaint != 0) { + nFinalizer(mNativePaint); + mNativePaint = 0; + } } finally { super.finalize(); } } - private static native long native_init(); - private static native long native_initWithPaint(long paint); - private static native void native_reset(long native_object); - private static native void native_set(long native_dst, long native_src); - private static native int native_getStyle(long native_object); - private static native void native_setStyle(long native_object, int style); - private static native int native_getStrokeCap(long native_object); - private static native void native_setStrokeCap(long native_object, int cap); - private static native int native_getStrokeJoin(long native_object); - private static native void native_setStrokeJoin(long native_object, + private static native long nInit(); + private static native long nInitWithPaint(long paint); + private static native void nReset(long paintPtr); + private static native void nSet(long paintPtrDest, long paintPtrSrc); + private static native int nGetStyle(long paintPtr); + private static native void nSetStyle(long paintPtr, int style); + private static native int nGetStrokeCap(long paintPtr); + private static native void nSetStrokeCap(long paintPtr, int cap); + private static native int nGetStrokeJoin(long paintPtr); + private static native void nSetStrokeJoin(long paintPtr, int join); - private static native boolean native_getFillPath(long native_object, + private static native boolean nGetFillPath(long paintPtr, long src, long dst); - private static native long native_setShader(long native_object, long shader); - private static native long native_setColorFilter(long native_object, + private static native long nSetShader(long paintPtr, long shader); + private static native long nSetColorFilter(long paintPtr, long filter); - private static native long native_setXfermode(long native_object, + private static native long nSetXfermode(long paintPtr, long xfermode); - private static native long native_setPathEffect(long native_object, + private static native long nSetPathEffect(long paintPtr, long effect); - private static native long native_setMaskFilter(long native_object, + private static native long nSetMaskFilter(long paintPtr, long maskfilter); - private static native long native_setTypeface(long native_object, + private static native long nSetTypeface(long paintPtr, long typeface); - private static native long native_setRasterizer(long native_object, + private static native long nSetRasterizer(long paintPtr, long rasterizer); - private static native int native_getTextAlign(long native_object); - private static native void native_setTextAlign(long native_object, + private static native int nGetTextAlign(long paintPtr); + private static native void nSetTextAlign(long paintPtr, int align); - private static native void native_setTextLocale(long native_object, + private static native void nSetTextLocale(long paintPtr, String locale); - private static native int native_getTextGlyphs(long native_object, - String text, int start, int end, int contextStart, int contextEnd, - int flags, char[] glyphs); - - private static native float native_getTextAdvances(long native_object, long native_typeface, + private static native float nGetTextAdvances(long paintPtr, long typefacePtr, char[] text, int index, int count, int contextIndex, int contextCount, int bidiFlags, float[] advances, int advancesIndex); - private static native float native_getTextAdvances(long native_object, long native_typeface, + private static native float nGetTextAdvances(long paintPtr, long typefacePtr, String text, int start, int end, int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex); - private native int native_getTextRunCursor(long native_object, char[] text, + private native int nGetTextRunCursor(long paintPtr, char[] text, int contextStart, int contextLength, int dir, int offset, int cursorOpt); - private native int native_getTextRunCursor(long native_object, String text, + private native int nGetTextRunCursor(long paintPtr, String text, int contextStart, int contextEnd, int dir, int offset, int cursorOpt); - private static native void native_getTextPath(long native_object, long native_typeface, + private static native void nGetTextPath(long paintPtr, long typefacePtr, int bidiFlags, char[] text, int index, int count, float x, float y, long path); - private static native void native_getTextPath(long native_object, long native_typeface, + private static native void nGetTextPath(long paintPtr, long typefacePtr, int bidiFlags, String text, int start, int end, float x, float y, long path); - private static native void nativeGetStringBounds(long nativePaint, long native_typeface, + private static native void nGetStringBounds(long nativePaint, long typefacePtr, String text, int start, int end, int bidiFlags, Rect bounds); - private static native void nativeGetCharArrayBounds(long nativePaint, long native_typeface, + private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr, char[] text, int index, int count, int bidiFlags, Rect bounds); - private static native void finalizer(long nativePaint); + private static native void nFinalizer(long nativePaint); - private static native void native_setShadowLayer(long native_object, + private static native void nSetShadowLayer(long paintPtr, float radius, float dx, float dy, int color); - private static native boolean native_hasShadowLayer(long native_object); + private static native boolean nHasShadowLayer(long paintPtr); - private static native float native_getLetterSpacing(long native_object); - private static native void native_setLetterSpacing(long native_object, + private static native float nGetLetterSpacing(long paintPtr); + private static native void nSetLetterSpacing(long paintPtr, float letterSpacing); - private static native void native_setFontFeatureSettings(long native_object, + private static native void nSetFontFeatureSettings(long paintPtr, String settings); - private static native int native_getHyphenEdit(long native_object); - private static native void native_setHyphenEdit(long native_object, int hyphen); - private static native boolean native_hasGlyph(long native_object, long native_typeface, + private static native int nGetHyphenEdit(long paintPtr); + private static native void nSetHyphenEdit(long paintPtr, int hyphen); + private static native boolean nHasGlyph(long paintPtr, long typefacePtr, int bidiFlags, String string); - private static native float native_getRunAdvance(long native_object, long native_typeface, + private static native float nGetRunAdvance(long paintPtr, long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset); - private static native int native_getOffsetForAdvance(long native_object, - long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd, + private static native int nGetOffsetForAdvance(long paintPtr, + long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance); } diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java index b67aa7dca17b..6763dd1970ae 100644 --- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java +++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java @@ -162,4 +162,60 @@ public class PaintTest extends AndroidTestCase { } catch (IndexOutOfBoundsException e) { } } + + public void testMeasureTextBidi() { + Paint p = new Paint(); + { + String bidiText = "abc \u0644\u063A\u0629 def"; + p.setBidiFlags(Paint.BIDI_LTR); + float width = p.measureText(bidiText, 0, 4); + p.setBidiFlags(Paint.BIDI_RTL); + width += p.measureText(bidiText, 4, 7); + p.setBidiFlags(Paint.BIDI_LTR); + width += p.measureText(bidiText, 7, bidiText.length()); + assertEquals(width, p.measureText(bidiText), 1.0f); + } + { + String bidiText = "abc \u0644\u063A\u0629 def"; + p.setBidiFlags(Paint.BIDI_DEFAULT_LTR); + float width = p.measureText(bidiText, 0, 4); + width += p.measureText(bidiText, 4, 7); + width += p.measureText(bidiText, 7, bidiText.length()); + assertEquals(width, p.measureText(bidiText), 1.0f); + } + { + String bidiText = "abc \u0644\u063A\u0629 def"; + p.setBidiFlags(Paint.BIDI_FORCE_LTR); + float width = p.measureText(bidiText, 0, 4); + width += p.measureText(bidiText, 4, 7); + width += p.measureText(bidiText, 7, bidiText.length()); + assertEquals(width, p.measureText(bidiText), 1.0f); + } + { + String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629"; + p.setBidiFlags(Paint.BIDI_RTL); + float width = p.measureText(bidiText, 0, 4); + p.setBidiFlags(Paint.BIDI_LTR); + width += p.measureText(bidiText, 4, 7); + p.setBidiFlags(Paint.BIDI_RTL); + width += p.measureText(bidiText, 7, bidiText.length()); + assertEquals(width, p.measureText(bidiText), 1.0f); + } + { + String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629"; + p.setBidiFlags(Paint.BIDI_DEFAULT_RTL); + float width = p.measureText(bidiText, 0, 4); + width += p.measureText(bidiText, 4, 7); + width += p.measureText(bidiText, 7, bidiText.length()); + assertEquals(width, p.measureText(bidiText), 1.0f); + } + { + String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629"; + p.setBidiFlags(Paint.BIDI_FORCE_RTL); + float width = p.measureText(bidiText, 0, 4); + width += p.measureText(bidiText, 4, 7); + width += p.measureText(bidiText, 7, bidiText.length()); + assertEquals(width, p.measureText(bidiText), 1.0f); + } + } } diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index e0bf26dd614d..0c29a9e928a2 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -44,6 +44,12 @@ namespace uirenderer { #define DEBUG_COLOR_MERGEDBATCH 0x5f7f7fff #define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f +static bool avoidOverdraw() { + // Don't avoid overdraw when visualizing it, since that makes it harder to + // debug where it's coming from, and when the problem occurs. + return !Properties::debugOverdraw; +}; + ///////////////////////////////////////////////////////////////////////////////// // Operation Batches ///////////////////////////////////////////////////////////////////////////////// @@ -218,7 +224,10 @@ public: // if paints are equal, then modifiers + paint attribs don't need to be compared if (op->mPaint == mOps[0].op->mPaint) return true; - if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false; + if (PaintUtils::getAlphaDirect(op->mPaint) + != PaintUtils::getAlphaDirect(mOps[0].op->mPaint)) { + return false; + } if (op->mPaint && mOps[0].op->mPaint && op->mPaint->getColorFilter() != mOps[0].op->mPaint->getColorFilter()) { @@ -495,7 +504,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { && mSaveStack.empty() && !state->mRoundRectClipState; - if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() && + if (CC_LIKELY(avoidOverdraw()) && mBatches.size() && state->mClipSideFlags != kClipSide_ConservativeFull && deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) { // avoid overdraw by resetting drawing state + discarding drawing ops @@ -647,7 +656,7 @@ void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) { // save and restore so that reordering doesn't affect final state renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); - if (CC_LIKELY(mAvoidOverdraw)) { + if (CC_LIKELY(avoidOverdraw())) { for (unsigned int i = 1; i < mBatches.size(); i++) { if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) { discardDrawingBatches(i - 1); diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h index 748bff628646..7873fbdd342a 100644 --- a/libs/hwui/DeferredDisplayList.h +++ b/libs/hwui/DeferredDisplayList.h @@ -83,8 +83,8 @@ public: class DeferredDisplayList { friend struct DeferStateStruct; // used to give access to allocator public: - DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) : - mBounds(bounds), mAvoidOverdraw(avoidOverdraw) { + DeferredDisplayList(const Rect& bounds) + : mBounds(bounds) { clear(); } ~DeferredDisplayList() { clear(); } @@ -152,7 +152,6 @@ private: // layer space bounds of rendering Rect mBounds; - const bool mAvoidOverdraw; /** * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 38f2363f3532..70383340fc8d 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -47,7 +47,8 @@ DeferredLayerUpdater::~DeferredLayerUpdater() { } void DeferredLayerUpdater::setPaint(const SkPaint* paint) { - OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode); + mAlpha = PaintUtils::getAlphaDirect(paint); + mMode = PaintUtils::getXfermodeDirect(paint); SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr; SkRefCnt_SafeAssign(mColorFilter, colorFilter); } diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index dc5cb8b349f1..ddfc533f9d77 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -172,10 +172,6 @@ public: void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; } bool getQuickRejected() { return mQuickRejected; } - inline int getPaintAlpha() const { - return OpenGLRenderer::getAlphaDirect(mPaint); - } - virtual bool hasTextShadow() const { return false; } @@ -213,7 +209,7 @@ protected: if (state.mAlpha != 1.0f) return false; - SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint); + SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint); return (mode == SkXfermode::kSrcOver_Mode || mode == SkXfermode::kSrc_Mode); @@ -249,8 +245,8 @@ public: virtual bool getLocalBounds(Rect& localBounds) override { localBounds.set(mLocalBounds); - OpenGLRenderer::TextShadow textShadow; - if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) { + PaintUtils::TextShadow textShadow; + if (PaintUtils::getTextShadow(mPaint, &textShadow)) { Rect shadow(mLocalBounds); shadow.translate(textShadow.dx, textShadow.dx); shadow.outset(textShadow.radius); @@ -372,8 +368,8 @@ public: private: bool isSaveLayerAlpha() const { - SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint); - int alpha = OpenGLRenderer::getAlphaDirect(mPaint); + SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint); + int alpha = PaintUtils::getAlphaDirect(mPaint); return alpha < 255 && mode == SkXfermode::kSrcOver_Mode; } @@ -691,7 +687,7 @@ public: // TODO: support clipped bitmaps by handling them in SET_TEXTURE deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() && !state.mClipSideFlags && - OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode && + PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode && (mBitmap->colorType() != kAlpha_8_SkColorType); } @@ -895,7 +891,7 @@ public: deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch; deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; deferInfo.mergeable = state.mMatrix.isPureTranslate() && - OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; + PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque(); } @@ -1241,7 +1237,7 @@ public: } virtual bool hasTextShadow() const override { - return OpenGLRenderer::hasTextShadow(mPaint); + return PaintUtils::hasTextShadow(mPaint); } virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, @@ -1330,7 +1326,7 @@ public: deferInfo.mergeable = state.mMatrix.isPureTranslate() && !hasDecorations - && OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; + && PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; } virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 4b9d4f90675c..ccf0b48cd4be 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -667,14 +667,6 @@ bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, cons return mDrawn; } -void FontRenderer::removeFont(const Font* font) { - mActiveFonts.remove(font->getDescription()); - - if (mCurrentFont == font) { - mCurrentFont = nullptr; - } -} - void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) { uint32_t intRadius = Blur::convertRadiusToInt(radius); #ifdef ANDROID_ENABLE_RENDERSCRIPT diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 936c838bd6e4..8172312e9a43 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -147,8 +147,6 @@ private: float x3, float y3, float u3, float v3, float x4, float y4, float u4, float v4, CacheTexture* texture); - void removeFont(const Font* font); - void checkTextureUpdate(); void setTextureDirty() { diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h index fa20b0807a88..4785ea48cddc 100644 --- a/libs/hwui/Glop.h +++ b/libs/hwui/Glop.h @@ -135,10 +135,6 @@ struct Glop { } fill; struct Transform { - // Orthographic projection matrix for current FBO - // TODO: move out of Glop, since this is static per FBO - Matrix4 ortho; - // modelView transform, accounting for delta between mesh transform and content of the mesh // often represents x/y offsets within command, or scaling for mesh unit size Matrix4 modelView; diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index 69559a77c3a0..fa166ae5ca5a 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -461,11 +461,10 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) { // Transform //////////////////////////////////////////////////////////////////////////////// -void GlopBuilder::setTransform(const Matrix4& ortho, const Matrix4& canvas, +void GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) { TRIGGER_STAGE(kTransformStage); - mOutGlop->transform.ortho = ortho; mOutGlop->transform.canvas = canvas; mOutGlop->transform.transformFlags = transformFlags; } diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 549bb21e5f8d..8d05570dd206 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -71,7 +71,7 @@ public: GlopBuilder& setFillTextureLayer(Layer& layer, float alpha); GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) { - setTransform(snapshot.getOrthoMatrix(), *snapshot.transform, transformFlags); + setTransform(*snapshot.transform, transformFlags); return *this; } @@ -102,8 +102,7 @@ private: void setFill(int color, float alphaScale, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage, const SkShader* shader, const SkColorFilter* colorFilter); - void setTransform(const Matrix4& ortho, const Matrix4& canvas, - const int transformFlags); + void setTransform(const Matrix4& canvas, const int transformFlags); enum StageFlags { kInitialStage = 0, diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 8d8528961794..f99d92b89420 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -170,7 +170,8 @@ void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, } void Layer::setPaint(const SkPaint* paint) { - OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode); + alpha = PaintUtils::getAlphaDirect(paint); + mode = PaintUtils::getXfermodeDirect(paint); setColorFilter((paint) ? paint->getColorFilter() : nullptr); } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index a401ce119021..9f24e379e418 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -540,7 +540,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float Rect bounds(left, top, right, bottom); Rect clip; calculateLayerBoundsAndClip(bounds, clip, true); - updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint)); + updateSnapshotIgnoreForLayer(bounds, clip, true, PaintUtils::getAlphaDirect(paint)); if (!mState.currentlyIgnored()) { writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); @@ -615,7 +615,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto Rect clip; Rect bounds(left, top, right, bottom); calculateLayerBoundsAndClip(bounds, clip, fboLayer); - updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint)); + updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, PaintUtils::getAlphaDirect(paint)); // Bail out if we won't draw in this snapshot if (mState.currentlyIgnored()) { @@ -1405,7 +1405,7 @@ void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) { setStencilFromClip(); } - mRenderState.render(glop); + mRenderState.render(glop, currentSnapshot()->getOrthoMatrix()); if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) { // TODO: specify more clearly when a draw should dirty the layer. // is writing to the stencil the only time we should ignore this? @@ -1431,10 +1431,7 @@ void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t return; } - // Don't avoid overdraw when visualizing, since that makes it harder to - // debug where it's coming from, and when the problem occurs. - bool avoidOverdraw = !Properties::debugOverdraw; - DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw); + DeferredDisplayList deferredList(mState.currentClipRect()); DeferStateStruct deferStruct(deferredList, *this, replayFlags); renderNode->defer(deferStruct, 0); @@ -1958,8 +1955,8 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, FontRenderer& fontRenderer, int alpha, float x, float y) { mCaches.textureState().activateTexture(0); - TextShadow textShadow; - if (!getTextShadow(paint, &textShadow)) { + PaintUtils::TextShadow textShadow; + if (!PaintUtils::getTextShadow(paint, &textShadow)) { LOG_ALWAYS_FATAL("failed to query shadow attributes"); } @@ -1987,8 +1984,10 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, renderGlop(glop); } +// TODO: remove this, once mState.currentlyIgnored captures snapshot alpha bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { - float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha; + float alpha = (PaintUtils::hasTextShadow(paint) + ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha; return MathUtils::isZero(alpha) && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; } @@ -2017,11 +2016,10 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); fontRenderer.setFont(paint, SkMatrix::I()); - int alpha; - SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); + int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; + SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); - if (CC_UNLIKELY(hasTextShadow(paint))) { + if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) { drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, 0.0f, 0.0f); } @@ -2162,13 +2160,12 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float y = floorf(y + transform.getTranslateY() + 0.5f); } - int alpha; - SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); + int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; + SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); - if (CC_UNLIKELY(hasTextShadow(paint))) { + if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) { fontRenderer.setFont(paint, SkMatrix::I()); drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, oldX, oldY); @@ -2238,9 +2235,8 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, fontRenderer.setFont(paint, SkMatrix::I()); fontRenderer.setTextureFiltering(true); - int alpha; - SkXfermode::Mode mode; - getAlphaAndMode(paint, &alpha, &mode); + int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; + SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint); const Rect* clip = &writableSnapshot()->getLocalClip(); @@ -2530,12 +2526,6 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot renderGlop(glop); } -void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, - SkXfermode::Mode* mode) const { - getAlphaAndModeDirect(paint, alpha, mode); - *alpha *= currentSnapshot()->alpha; -} - float OpenGLRenderer::getLayerAlpha(const Layer* layer) const { return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha; } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 910af5705705..400c225b53a0 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -260,57 +260,6 @@ public: void endMark() const; /** - * Gets the alpha and xfermode out of a paint object. If the paint is null - * alpha will be 255 and the xfermode will be SRC_OVER. This method does - * not multiply the paint's alpha by the current snapshot's alpha, and does - * not replace the alpha with the overrideLayerAlpha - * - * @param paint The paint to extract values from - * @param alpha Where to store the resulting alpha - * @param mode Where to store the resulting xfermode - */ - static inline void getAlphaAndModeDirect(const SkPaint* paint, int* alpha, - SkXfermode::Mode* mode) { - *mode = getXfermodeDirect(paint); - *alpha = getAlphaDirect(paint); - } - - static inline SkXfermode::Mode getXfermodeDirect(const SkPaint* paint) { - if (!paint) return SkXfermode::kSrcOver_Mode; - return PaintUtils::getXfermode(paint->getXfermode()); - } - - static inline int getAlphaDirect(const SkPaint* paint) { - if (!paint) return 255; - return paint->getAlpha(); - } - - struct TextShadow { - SkScalar radius; - float dx; - float dy; - SkColor color; - }; - - static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) { - SkDrawLooper::BlurShadowRec blur; - if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) { - if (textShadow) { - textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma); - textShadow->dx = blur.fOffset.fX; - textShadow->dy = blur.fOffset.fY; - textShadow->color = blur.fColor; - } - return true; - } - return false; - } - - static inline bool hasTextShadow(const SkPaint* paint) { - return getTextShadow(paint, nullptr); - } - - /** * Build the best transform to use to rasterize text given a full * transform matrix, and whether filteration is needed. * @@ -493,16 +442,6 @@ protected: void drawTextureLayer(Layer* layer, const Rect& rect); /** - * Gets the alpha and xfermode out of a paint object. If the paint is null - * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for snapshot alpha. - * - * @param paint The paint to extract values from - * @param alpha Where to store the resulting alpha - * @param mode Where to store the resulting xfermode - */ - inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const; - - /** * Gets the alpha from a layer, accounting for snapshot alpha * * @param layer The layer from which the alpha is extracted diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index ddc7ecd329b6..bf1b4d0b0d0e 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -725,7 +725,9 @@ template <class T> void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) { if (properties().getAlpha() <= 0.0f || properties().getOutline().getAlpha() <= 0.0f - || !properties().getOutline().getPath()) { + || !properties().getOutline().getPath() + || properties().getScaleX() == 0 + || properties().getScaleY() == 0) { // no shadow to draw return; } @@ -915,7 +917,10 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { const bool useViewProperties = (!mLayer || drawLayer); if (useViewProperties) { const Outline& outline = properties().getOutline(); - if (properties().getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty())) { + if (properties().getAlpha() <= 0 + || (outline.getShouldClip() && outline.isEmpty()) + || properties().getScaleX() == 0 + || properties().getScaleY() == 0) { DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", handler.level() * 2, "", this, getName()); return; diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index ad74bff8dc25..ce1bd6ab8b03 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -52,11 +52,8 @@ bool LayerProperties::setColorFilter(SkColorFilter* filter) { bool LayerProperties::setFromPaint(const SkPaint* paint) { bool changed = false; - SkXfermode::Mode mode; - int alpha; - OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode); - changed |= setAlpha(static_cast<uint8_t>(alpha)); - changed |= setXferMode(mode); + changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint))); + changed |= setXferMode(PaintUtils::getXfermodeDirect(paint)); changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr); return changed; } diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index 220936551a60..eb0fa74f5af0 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -73,8 +73,8 @@ void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque, } #if DEBUG_SHADOW - ALOGD("light center %f %f %f", - adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z); + ALOGD("light center %f %f %f %d", + adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z, lightRadius); #endif // light position (because it's in local space) needs to compensate for receiver transform diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 9b0a1aadf0bf..bdce73c79993 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -1051,7 +1051,7 @@ void SpotShadow::dumpPolygon(const Vector2* poly, int polyLength, const char* po */ void SpotShadow::dumpPolygon(const Vector3* poly, int polyLength, const char* polyName) { for (int i = 0; i < polyLength; i++) { - ALOGD("polygon %s i %d x %f y %f", polyName, i, poly[i].x, poly[i].y); + ALOGD("polygon %s i %d x %f y %f z %f", polyName, i, poly[i].x, poly[i].y, poly[i].z); } } diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index fb0753bbc76c..d680f990a0be 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -61,8 +61,6 @@ Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& ras } Font::~Font() { - mState->removeFont(this); - for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { delete mCachedGlyphs.valueAt(i); } diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index c5126def683c..dfa70ace2f44 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -208,7 +208,7 @@ void RenderState::postDecStrong(VirtualLightRefBase* object) { // Render /////////////////////////////////////////////////////////////////////////////// -void RenderState::render(const Glop& glop) { +void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { const Glop::Mesh& mesh = glop.mesh; const Glop::Mesh::Vertices& vertices = mesh.vertices; const Glop::Mesh::Indices& indices = mesh.indices; @@ -223,7 +223,7 @@ void RenderState::render(const Glop& glop) { fill.program->setColor(fill.color); } - fill.program->set(glop.transform.ortho, + fill.program->set(orthoMatrix, glop.transform.modelView, glop.transform.meshTransform(), glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor); diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index 4fd792c1b503..9ae084506f1d 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -84,7 +84,7 @@ public: // more thinking... void postDecStrong(VirtualLightRefBase* object); - void render(const Glop& glop); + void render(const Glop& glop, const Matrix4& orthoMatrix); AssetAtlas& assetAtlas() { return mAssetAtlas; } Blend& blend() { return *mBlend; } diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9dc5b45a7738..ddfd62141f5d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -62,7 +62,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) , mJankTracker(thread.timeLord().frameIntervalNanos()) , mProfiler(mFrames) - , mContentOverdrawProtectionBounds(0, 0, 0, 0) { + , mContentDrawBounds(0, 0, 0, 0) { mRenderNodes.emplace_back(rootRenderNode); mRenderThread.renderState().registerCanvasContext(this); mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); @@ -309,7 +309,7 @@ void CanvasContext::draw() { Rect outBounds; // It there are multiple render nodes, they are as follows: // #0 - backdrop - // #1 - content (with - and clipped to - bounds mContentOverdrawProtectionBounds) + // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds) // #2 - frame // Usually the backdrop cannot be seen since it will be entirely covered by the content. While // resizing however it might become partially visible. The following render loop will crop the @@ -317,66 +317,72 @@ void CanvasContext::draw() { // against the backdrop (since that indicates a shrinking of the window) and then the frame // around everything. // The bounds of the backdrop against which the content should be clipped. - Rect backdropBounds = mContentOverdrawProtectionBounds; + Rect backdropBounds = mContentDrawBounds; + // Usually the contents bounds should be mContentDrawBounds - however - we will + // move it towards the fixed edge to give it a more stable appearance (for the moment). + Rect contentBounds; // If there is no content bounds we ignore the layering as stated above and start with 2. - int layer = mContentOverdrawProtectionBounds.isEmpty() ? 2 : 0; + int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() <= 2) ? 2 : 0; // Draw all render nodes. Note that for (const sp<RenderNode>& node : mRenderNodes) { if (layer == 0) { // Backdrop. - // Draw the backdrop clipped to the inverse content bounds. + // Draw the backdrop clipped to the inverse content bounds, but assume that the content + // was moved to the upper left corner. const RenderProperties& properties = node->properties(); Rect targetBounds(properties.getLeft(), properties.getTop(), properties.getRight(), properties.getBottom()); + // Move the content bounds towards the fixed corner of the backdrop. + const int x = targetBounds.left; + const int y = targetBounds.top; + contentBounds.set(x, y, x + mContentDrawBounds.getWidth(), + y + mContentDrawBounds.getHeight()); // Remember the intersection of the target bounds and the intersection bounds against // which we have to crop the content. + backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight()); backdropBounds.intersect(targetBounds); // Check if we have to draw something on the left side ... - if (targetBounds.left < mContentOverdrawProtectionBounds.left) { + if (targetBounds.left < contentBounds.left) { mCanvas->save(SkCanvas::kClip_SaveFlag); if (mCanvas->clipRect(targetBounds.left, targetBounds.top, - mContentOverdrawProtectionBounds.left, targetBounds.bottom, + contentBounds.left, targetBounds.bottom, SkRegion::kIntersect_Op)) { mCanvas->drawRenderNode(node.get(), outBounds); } // Reduce the target area by the area we have just painted. - targetBounds.left = std::min(mContentOverdrawProtectionBounds.left, - targetBounds.right); + targetBounds.left = std::min(contentBounds.left, targetBounds.right); mCanvas->restore(); } // ... or on the right side ... - if (targetBounds.right > mContentOverdrawProtectionBounds.right && + if (targetBounds.right > contentBounds.right && !targetBounds.isEmpty()) { mCanvas->save(SkCanvas::kClip_SaveFlag); - if (mCanvas->clipRect(mContentOverdrawProtectionBounds.right, targetBounds.top, + if (mCanvas->clipRect(contentBounds.right, targetBounds.top, targetBounds.right, targetBounds.bottom, SkRegion::kIntersect_Op)) { mCanvas->drawRenderNode(node.get(), outBounds); } // Reduce the target area by the area we have just painted. - targetBounds.right = std::max(targetBounds.left, - mContentOverdrawProtectionBounds.right); + targetBounds.right = std::max(targetBounds.left, contentBounds.right); mCanvas->restore(); } // ... or at the top ... - if (targetBounds.top < mContentOverdrawProtectionBounds.top && + if (targetBounds.top < contentBounds.top && !targetBounds.isEmpty()) { mCanvas->save(SkCanvas::kClip_SaveFlag); if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right, - mContentOverdrawProtectionBounds.top, + contentBounds.top, SkRegion::kIntersect_Op)) { mCanvas->drawRenderNode(node.get(), outBounds); } // Reduce the target area by the area we have just painted. - targetBounds.top = std::min(mContentOverdrawProtectionBounds.top, - targetBounds.bottom); + targetBounds.top = std::min(contentBounds.top, targetBounds.bottom); mCanvas->restore(); } // ... or at the bottom. - if (targetBounds.bottom > mContentOverdrawProtectionBounds.bottom && + if (targetBounds.bottom > contentBounds.bottom && !targetBounds.isEmpty()) { mCanvas->save(SkCanvas::kClip_SaveFlag); - if (mCanvas->clipRect(targetBounds.left, - mContentOverdrawProtectionBounds.bottom, targetBounds.right, + if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right, targetBounds.bottom, SkRegion::kIntersect_Op)) { mCanvas->drawRenderNode(node.get(), outBounds); } @@ -384,10 +390,17 @@ void CanvasContext::draw() { } } else if (layer == 1) { // Content // It gets cropped against the bounds of the backdrop to stay inside. - mCanvas->save(SkCanvas::kClip_SaveFlag); - if (mCanvas->clipRect(backdropBounds.left, backdropBounds.top, - backdropBounds.right, backdropBounds.bottom, - SkRegion::kIntersect_Op)) { + mCanvas->save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); + + // We shift and clip the content to match its final location in the window. + const float left = mContentDrawBounds.left; + const float top = mContentDrawBounds.top; + const float dx = backdropBounds.left - left; + const float dy = backdropBounds.top - top; + const float width = backdropBounds.getWidth(); + const float height = backdropBounds.getHeight(); + mCanvas->translate(dx, dy); + if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) { mCanvas->drawRenderNode(node.get(), outBounds); } mCanvas->restore(); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 1c3845cac504..e0cbabdc933a 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -126,8 +126,8 @@ public: mRenderNodes.end()); } - void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) { - mContentOverdrawProtectionBounds.set(left, top, right, bottom); + void setContentDrawBounds(int left, int top, int right, int bottom) { + mContentDrawBounds.set(left, top, right, bottom); } private: @@ -167,7 +167,7 @@ private: std::set<RenderNode*> mPrefetechedLayers; // Stores the bounds of the main content. - Rect mContentOverdrawProtectionBounds; + Rect mContentDrawBounds; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index f43a769890a4..26aae90d5990 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -529,15 +529,14 @@ void RenderProxy::drawRenderNode(RenderNode* node) { staticPostAndWait(task); } -CREATE_BRIDGE5(setContentOverdrawProtectionBounds, CanvasContext* context, int left, int top, +CREATE_BRIDGE5(setContentDrawBounds, CanvasContext* context, int left, int top, int right, int bottom) { - args->context->setContentOverdrawProtectionBounds(args->left, args->top, args->right, - args->bottom); + args->context->setContentDrawBounds(args->left, args->top, args->right, args->bottom); return nullptr; } -void RenderProxy::setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) { - SETUP_TASK(setContentOverdrawProtectionBounds); +void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) { + SETUP_TASK(setContentDrawBounds); args->context = mContext; args->left = left; args->top = top; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 046f24ac3f81..d1b62f1f64a6 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -109,7 +109,7 @@ public: ANDROID_API void addRenderNode(RenderNode* node, bool placeFront); ANDROID_API void removeRenderNode(RenderNode* node); ANDROID_API void drawRenderNode(RenderNode* node); - ANDROID_API void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom); + ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom); private: RenderThread& mRenderThread; diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h index ba02f5f1a77d..d00236ed955a 100644 --- a/libs/hwui/utils/PaintUtils.h +++ b/libs/hwui/utils/PaintUtils.h @@ -16,12 +16,19 @@ #ifndef PAINT_UTILS_H #define PAINT_UTILS_H +#include <utils/Blur.h> + #include <SkColorFilter.h> +#include <SkDrawLooper.h> #include <SkXfermode.h> namespace android { namespace uirenderer { +/** + * Utility methods for accessing data within SkPaint, and providing defaults + * with optional SkPaint pointers. + */ class PaintUtils { public: @@ -73,6 +80,39 @@ public: return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0; } + struct TextShadow { + SkScalar radius; + float dx; + float dy; + SkColor color; + }; + + static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) { + SkDrawLooper::BlurShadowRec blur; + if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) { + if (textShadow) { + textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma); + textShadow->dx = blur.fOffset.fX; + textShadow->dy = blur.fOffset.fY; + textShadow->color = blur.fColor; + } + return true; + } + return false; + } + + static inline bool hasTextShadow(const SkPaint* paint) { + return getTextShadow(paint, nullptr); + } + + static inline SkXfermode::Mode getXfermodeDirect(const SkPaint* paint) { + return paint ? getXfermode(paint->getXfermode()) : SkXfermode::kSrcOver_Mode; + } + + static inline int getAlphaDirect(const SkPaint* paint) { + return paint ? paint->getAlpha() : 255; + } + }; // class PaintUtils } /* namespace uirenderer */ diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java index 54ad60e4a62d..4b8f81e01a1d 100644 --- a/media/java/android/media/Metadata.java +++ b/media/java/android/media/Metadata.java @@ -18,6 +18,7 @@ package android.media; import android.os.Parcel; import android.util.Log; +import android.util.MathUtils; import java.util.Calendar; import java.util.Collections; @@ -332,7 +333,14 @@ import java.util.TimeZone; } // Skip to the next one. - parcel.setDataPosition(start + size); + try { + parcel.setDataPosition(MathUtils.addOrThrow(start, size)); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Invalid size: " + e.getMessage()); + error = true; + break; + } + bytesLeft -= size; ++recCount; } diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml index 673a254f63f5..7e0649be722d 100644 --- a/packages/DocumentsUI/res/menu/activity.xml +++ b/packages/DocumentsUI/res/menu/activity.xml @@ -23,13 +23,6 @@ android:actionViewClass="android.widget.SearchView" android:imeOptions="actionSearch" /> <item - android:id="@+id/menu_create_dir" - android:title="@string/menu_create_dir" - android:icon="@drawable/ic_menu_new_folder" - android:alphabeticShortcut="e" - android:showAsAction="always" - android:visible="false" /> - <item android:id="@+id/menu_sort" android:title="@string/menu_sort" android:icon="@drawable/ic_menu_sortby" @@ -63,6 +56,13 @@ android:showAsAction="never" android:visible="false" /> <item + android:id="@+id/menu_create_dir" + android:title="@string/menu_create_dir" + android:icon="@drawable/ic_menu_new_folder" + android:alphabeticShortcut="e" + android:showAsAction="always" + android:visible="false" /> + <item android:id="@+id/menu_paste_from_clipboard" android:title="@string/menu_paste_from_clipboard" android:alphabeticShortcut="v" @@ -70,11 +70,11 @@ android:visible="false" /> <!-- Copy action is defined in mode_directory.xml --> <item - android:id="@+id/menu_advanced" + android:id="@+id/menu_file_size" android:showAsAction="never" android:visible="false" /> <item - android:id="@+id/menu_file_size" + android:id="@+id/menu_advanced" android:showAsAction="never" android:visible="false" /> <item diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml index c2b6dbcaa791..ba92c00b7c1f 100644 --- a/packages/DocumentsUI/res/values-af/strings.xml +++ b/packages/DocumentsUI/res/values-af/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Lêers"</string> <string name="title_open" msgid="4353228937663917801">"Maak oop vanuit"</string> <string name="title_save" msgid="2433679664882857999">"Stoor na"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Skep vouer"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Roosteraansig"</string> <string name="menu_list" msgid="7279285939892417279">"Lysaansig"</string> <string name="menu_sort" msgid="7677740407158414452">"Sorteer volgens"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Kies alles"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopieer na …"</string> <string name="menu_move" msgid="1828090633118079817">"Skuif na …"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nuwe venster"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopieer"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Plak"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Wys interne berging"</string> diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml index b82fa937fbac..7fb3b740e1d3 100644 --- a/packages/DocumentsUI/res/values-am/strings.xml +++ b/packages/DocumentsUI/res/values-am/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ፋይሎች"</string> <string name="title_open" msgid="4353228937663917801">"ክፈት ከ"</string> <string name="title_save" msgid="2433679664882857999">"አስቀምጥ ወደ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"አቃፊ ፍጠር"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"የፍርግርግ እይታ"</string> <string name="menu_list" msgid="7279285939892417279">"የዝርዝር እይታ"</string> <string name="menu_sort" msgid="7677740407158414452">"ደርድር በ"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"ሁሉንም ምረጥ"</string> <string name="menu_copy" msgid="3612326052677229148">"ቅዳ ወደ…"</string> <string name="menu_move" msgid="1828090633118079817">"ይውሰዱ ወደ..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"አዲሰ መስኮት"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ቅዳ"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ለጥፍ"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ውስጣዊ ማከማቻ አሳይ"</string> diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml index c7c9ef2405a7..b61d190ad4dc 100644 --- a/packages/DocumentsUI/res/values-ar/strings.xml +++ b/packages/DocumentsUI/res/values-ar/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"الملفات"</string> <string name="title_open" msgid="4353228937663917801">"فتح من"</string> <string name="title_save" msgid="2433679664882857999">"حفظ في"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"إنشاء مجلد"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"عرض الشبكة"</string> <string name="menu_list" msgid="7279285939892417279">"عرض القائمة"</string> <string name="menu_sort" msgid="7677740407158414452">"ترتيب بحسب"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"تحديد الكل"</string> <string name="menu_copy" msgid="3612326052677229148">"نسخ إلى…"</string> <string name="menu_move" msgid="1828090633118079817">"نقل إلى..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"نافذة جديدة"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"نسخ"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"لصق"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"إظهار وحدة التخزين الداخلية"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"نسخ"</string> <string name="button_move" msgid="2202666023104202232">"نقل"</string> <string name="button_dismiss" msgid="3714065566893946085">"إزالة"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"إعادة المحاولة"</string> <string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string> <string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string> <string name="sort_size" msgid="3350681319735474741">"بحسب الحجم"</string> diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml index 8c79cebca33f..dc3827ee8e98 100644 --- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml +++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fayllar"</string> <string name="title_open" msgid="4353228937663917801">"Vasitəsilə açın"</string> <string name="title_save" msgid="2433679664882857999">"buraya saxlayın"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Qovluq yaradın"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Torlu görünüş"</string> <string name="menu_list" msgid="7279285939892417279">"Siyahı görünüşü"</string> <string name="menu_sort" msgid="7677740407158414452">"Bunlardan biri üzrə sırala"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Hamısını seçin"</string> <string name="menu_copy" msgid="3612326052677229148">"Buraya kopyalayın:"</string> <string name="menu_move" msgid="1828090633118079817">"Köçürün…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Yeni pəncərə"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopyalayın"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Yerləşdirin"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Daxili yaddaşı göstərin"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string> <string name="button_move" msgid="2202666023104202232">"Köçürün"</string> <string name="button_dismiss" msgid="3714065566893946085">"Rədd edin"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Yenidən cəhd edin"</string> <string name="sort_name" msgid="9183560467917256779">"Ad üzrə"</string> <string name="sort_date" msgid="586080032956151448">"Tarix üzrə dəyişmiş"</string> <string name="sort_size" msgid="3350681319735474741">"Ölçü üzrə"</string> diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml index fdf57d091926..e8c5822a7308 100644 --- a/packages/DocumentsUI/res/values-bg/strings.xml +++ b/packages/DocumentsUI/res/values-bg/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Файлове"</string> <string name="title_open" msgid="4353228937663917801">"Отваряне от"</string> <string name="title_save" msgid="2433679664882857999">"Запазване във:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Създаване на папка"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Изглед в мрежа"</string> <string name="menu_list" msgid="7279285939892417279">"Списъчен изглед"</string> <string name="menu_sort" msgid="7677740407158414452">"Сортиране по"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Избиране на всичко"</string> <string name="menu_copy" msgid="3612326052677229148">"Копиране във…"</string> <string name="menu_move" msgid="1828090633118079817">"Преместване във…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Нов прозорец"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копиране"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Поставяне"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Вътр. хранилище: Показв."</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Копиране"</string> <string name="button_move" msgid="2202666023104202232">"Преместване"</string> <string name="button_dismiss" msgid="3714065566893946085">"Отхвърляне"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Нов опит"</string> <string name="sort_name" msgid="9183560467917256779">"По име"</string> <string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string> <string name="sort_size" msgid="3350681319735474741">"По размер"</string> diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml index 7caf57fbbed7..dc20b16ae1cc 100644 --- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml +++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ফাইলগুলি"</string> <string name="title_open" msgid="4353228937663917801">"এখান থেকে খুলুন"</string> <string name="title_save" msgid="2433679664882857999">"এতে সংরক্ষণ করুন"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ফোল্ডার তৈরি করুন"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"গ্রিড দৃশ্য"</string> <string name="menu_list" msgid="7279285939892417279">"তালিকা দৃশ্য"</string> <string name="menu_sort" msgid="7677740407158414452">"এই অনুসারে বাছুন"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"সবগুলি নির্বাচন করুন"</string> <string name="menu_copy" msgid="3612326052677229148">"এতে অনুলিপি করুন…"</string> <string name="menu_move" msgid="1828090633118079817">"এতে সরান..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"নতুন উইন্ডো"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"প্রতিলিপি করুন"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"আটকান"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"অভ্যন্তরীণ সঞ্চয়স্থান দেখান"</string> diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml index ab365ce82801..ab90f1fb4a53 100644 --- a/packages/DocumentsUI/res/values-ca/strings.xml +++ b/packages/DocumentsUI/res/values-ca/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fitxers"</string> <string name="title_open" msgid="4353228937663917801">"Obre des de"</string> <string name="title_save" msgid="2433679664882857999">"Desa a"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Crea una carpeta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Visualització de quadrícula"</string> <string name="menu_list" msgid="7279285939892417279">"Visualització de llista"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordena per"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Selecciona-ho tot"</string> <string name="menu_copy" msgid="3612326052677229148">"Copia a…"</string> <string name="menu_move" msgid="1828090633118079817">"Mou a..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Finestra nova"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copia"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Enganxa"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra emmagatz. intern"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Copia"</string> <string name="button_move" msgid="2202666023104202232">"Desplaça"</string> <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Torna-ho a provar"</string> <string name="sort_name" msgid="9183560467917256779">"Per nom"</string> <string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string> <string name="sort_size" msgid="3350681319735474741">"Per mida"</string> diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml index 62b313c94bdc..9b1b0c8c52f8 100644 --- a/packages/DocumentsUI/res/values-cs/strings.xml +++ b/packages/DocumentsUI/res/values-cs/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Soubory"</string> <string name="title_open" msgid="4353228937663917801">"Otevřít"</string> <string name="title_save" msgid="2433679664882857999">"Uložit do"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Vytvořit složku"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Mřížkové zobrazení"</string> <string name="menu_list" msgid="7279285939892417279">"Zobrazení seznamu"</string> <string name="menu_sort" msgid="7677740407158414452">"Řadit podle"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Vybrat vše"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopírovat do…"</string> <string name="menu_move" msgid="1828090633118079817">"Přesunout do…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nové okno"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopírovat"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Vložit"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobrazit inter. úložiště"</string> diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml index c3d7cdd39d08..284d87e200c6 100644 --- a/packages/DocumentsUI/res/values-da/strings.xml +++ b/packages/DocumentsUI/res/values-da/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Filer"</string> <string name="title_open" msgid="4353228937663917801">"Åbn fra"</string> <string name="title_save" msgid="2433679664882857999">"Gem i"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Opret mappe"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Gittervisning"</string> <string name="menu_list" msgid="7279285939892417279">"Listevisning"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortér efter"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Markér alle"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiér til…"</string> <string name="menu_move" msgid="1828090633118079817">"Flyt til…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nyt vindue"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiér"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Indsæt"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis intern lagerplads"</string> diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml index f88b5c4cb92e..1fe53ff88667 100644 --- a/packages/DocumentsUI/res/values-de/strings.xml +++ b/packages/DocumentsUI/res/values-de/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Dateien"</string> <string name="title_open" msgid="4353228937663917801">"Öffnen von"</string> <string name="title_save" msgid="2433679664882857999">"Speichern unter"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Ordner erstellen"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Rasteransicht"</string> <string name="menu_list" msgid="7279285939892417279">"Listenansicht"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortieren nach"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Alle auswählen"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopieren nach..."</string> <string name="menu_move" msgid="1828090633118079817">"Verschieben nach…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Neues Fenster"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopieren"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Einfügen"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Int. Speicher anzeigen"</string> diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml index dcca46c776b2..e9743eee88bc 100644 --- a/packages/DocumentsUI/res/values-el/strings.xml +++ b/packages/DocumentsUI/res/values-el/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Αρχεία"</string> <string name="title_open" msgid="4353228937663917801">"Άνοιγμα από"</string> <string name="title_save" msgid="2433679664882857999">"Αποθήκευση σε"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Δημιουργία φακέλου"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Προβολή πλέγματος"</string> <string name="menu_list" msgid="7279285939892417279">"Προβολή λίστας"</string> <string name="menu_sort" msgid="7677740407158414452">"Ταξινόμηση κατά"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Επιλογή όλων"</string> <string name="menu_copy" msgid="3612326052677229148">"Αντιγραφή σε…"</string> <string name="menu_move" msgid="1828090633118079817">"Μετακίνηση σε..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Νέο παράθυρο"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Αντιγραφή"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Επικόλληση"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Εμφ.εσωτ.χώρου αποθήκ."</string> diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml index 26fd30ff9d38..03399e263efd 100644 --- a/packages/DocumentsUI/res/values-en-rAU/strings.xml +++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Files"</string> <string name="title_open" msgid="4353228937663917801">"Open from"</string> <string name="title_save" msgid="2433679664882857999">"Save to"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Create folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Grid view"</string> <string name="menu_list" msgid="7279285939892417279">"List view"</string> <string name="menu_sort" msgid="7677740407158414452">"Sort by"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Select all"</string> <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string> <string name="menu_move" msgid="1828090633118079817">"Move to…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"New window"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copy"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Paste"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string> diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml index 26fd30ff9d38..03399e263efd 100644 --- a/packages/DocumentsUI/res/values-en-rGB/strings.xml +++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Files"</string> <string name="title_open" msgid="4353228937663917801">"Open from"</string> <string name="title_save" msgid="2433679664882857999">"Save to"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Create folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Grid view"</string> <string name="menu_list" msgid="7279285939892417279">"List view"</string> <string name="menu_sort" msgid="7677740407158414452">"Sort by"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Select all"</string> <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string> <string name="menu_move" msgid="1828090633118079817">"Move to…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"New window"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copy"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Paste"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string> diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml index 26fd30ff9d38..03399e263efd 100644 --- a/packages/DocumentsUI/res/values-en-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Files"</string> <string name="title_open" msgid="4353228937663917801">"Open from"</string> <string name="title_save" msgid="2433679664882857999">"Save to"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Create folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Grid view"</string> <string name="menu_list" msgid="7279285939892417279">"List view"</string> <string name="menu_sort" msgid="7677740407158414452">"Sort by"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Select all"</string> <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string> <string name="menu_move" msgid="1828090633118079817">"Move to…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"New window"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copy"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Paste"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string> diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml index 6e805b90d4e4..cc99d7f0e94d 100644 --- a/packages/DocumentsUI/res/values-es-rUS/strings.xml +++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Archivos"</string> <string name="title_open" msgid="4353228937663917801">"Abrir desde"</string> <string name="title_save" msgid="2433679664882857999">"Guardar en"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Crear carpeta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Vista de cuadrícula"</string> <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Seleccionar todo"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiar a…"</string> <string name="menu_move" msgid="1828090633118079817">"Mover a…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Ventana nueva"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Pegar"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string> diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml index 8fa1d2ed4c63..83403e074ebd 100644 --- a/packages/DocumentsUI/res/values-es/strings.xml +++ b/packages/DocumentsUI/res/values-es/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Archivos"</string> <string name="title_open" msgid="4353228937663917801">"Abrir desde"</string> <string name="title_save" msgid="2433679664882857999">"Guardar en"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Crear carpeta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Vista de cuadrícula"</string> <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Seleccionar todo"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiar en…"</string> <string name="menu_move" msgid="1828090633118079817">"Mover a…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nueva ventana"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Pegar"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almac. interno"</string> diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml index 7008885bd348..b38fcd99cf3e 100644 --- a/packages/DocumentsUI/res/values-et-rEE/strings.xml +++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Failid"</string> <string name="title_open" msgid="4353228937663917801">"Ava:"</string> <string name="title_save" msgid="2433679664882857999">"Salvesta:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Loo kaust"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Ruudustikkuva"</string> <string name="menu_list" msgid="7279285939892417279">"Loendikuva"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortimisalus:"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Vali kõik"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopeeri asukohta ..."</string> <string name="menu_move" msgid="1828090633118079817">"Teisaldamine kohta ..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Uus aken"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopeeri"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Kleebi"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Kuva sis. salvestusruum"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopeeri"</string> <string name="button_move" msgid="2202666023104202232">"Teisalda"</string> <string name="button_dismiss" msgid="3714065566893946085">"Loobu"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Proovi uuesti"</string> <string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string> <string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string> <string name="sort_size" msgid="3350681319735474741">"Suuruse järgi"</string> diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml index 17d7c660a1bb..9939b1d40255 100644 --- a/packages/DocumentsUI/res/values-eu-rES/strings.xml +++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fitxategiak"</string> <string name="title_open" msgid="4353228937663917801">"Ireki hemendik"</string> <string name="title_save" msgid="2433679664882857999">"Gorde hemen"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Sortu karpeta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Sareta-ikuspegia"</string> <string name="menu_list" msgid="7279285939892417279">"Zerrenda-ikuspegia"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordenatzeko irizpidea"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Hautatu guztiak"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiatu hemen…"</string> <string name="menu_move" msgid="1828090633118079817">"Eraman hona…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Leiho berria"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiatu"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Itsatsi"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Erakutsi barneko memoria"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopiatu"</string> <string name="button_move" msgid="2202666023104202232">"Mugitu"</string> <string name="button_dismiss" msgid="3714065566893946085">"Baztertu"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Saiatu berriro"</string> <string name="sort_name" msgid="9183560467917256779">"Izenaren arabera"</string> <string name="sort_date" msgid="586080032956151448">"Aldatze-dataren arabera"</string> <string name="sort_size" msgid="3350681319735474741">"Tamainaren arabera"</string> diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml index c4f6d588ea1c..297e4a16fea9 100644 --- a/packages/DocumentsUI/res/values-fa/strings.xml +++ b/packages/DocumentsUI/res/values-fa/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"فایلها"</string> <string name="title_open" msgid="4353228937663917801">"باز کردن از"</string> <string name="title_save" msgid="2433679664882857999">"ذخیره در"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ایجاد پوشه"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"نمای جدولی"</string> <string name="menu_list" msgid="7279285939892417279">"نمای فهرستی"</string> <string name="menu_sort" msgid="7677740407158414452">"مرتبسازی براساس"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"انتخاب همه"</string> <string name="menu_copy" msgid="3612326052677229148">"کپی در..."</string> <string name="menu_move" msgid="1828090633118079817">"انتقال به…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"پنجره جدید"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"کپی"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"جایگذاری"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"نمایش فضای ذخیرهسازی داخلی"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"کپی"</string> <string name="button_move" msgid="2202666023104202232">"انتقال"</string> <string name="button_dismiss" msgid="3714065566893946085">"نپذیرفتن"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"دوباره امتحان کنید"</string> <string name="sort_name" msgid="9183560467917256779">"براساس نام"</string> <string name="sort_date" msgid="586080032956151448">"براساس تاریخ اصلاح"</string> <string name="sort_size" msgid="3350681319735474741">"براساس اندازه"</string> diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml index 3e873009ce7a..a4c742a20489 100644 --- a/packages/DocumentsUI/res/values-fi/strings.xml +++ b/packages/DocumentsUI/res/values-fi/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Tiedostot"</string> <string name="title_open" msgid="4353228937663917801">"Avaa sijainnista"</string> <string name="title_save" msgid="2433679664882857999">"Tallenna kohteeseen"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Luo kansio"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Ruudukkonäkymä"</string> <string name="menu_list" msgid="7279285939892417279">"Luettelonäkymä"</string> <string name="menu_sort" msgid="7677740407158414452">"Lajitteluperuste"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Valitse kaikki"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopioi kohteeseen…"</string> <string name="menu_move" msgid="1828090633118079817">"Siirrä kohteeseen…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Uusi ikkuna"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopioi"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Liitä"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Näytä sis. tallennustila"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopioi"</string> <string name="button_move" msgid="2202666023104202232">"Siirrä"</string> <string name="button_dismiss" msgid="3714065566893946085">"Hylkää"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Yritä uudelleen"</string> <string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string> <string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string> <string name="sort_size" msgid="3350681319735474741">"Koon mukaan"</string> diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml index 3e82f3403cdc..80cd0b212f29 100644 --- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml +++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fichiers"</string> <string name="title_open" msgid="4353228937663917801">"Ouvrir à partir de"</string> <string name="title_save" msgid="2433679664882857999">"Enregistrer dans"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Créer un dossier"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Grille"</string> <string name="menu_list" msgid="7279285939892417279">"Liste"</string> <string name="menu_sort" msgid="7677740407158414452">"Trier par"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Tout sélectionner"</string> <string name="menu_copy" msgid="3612326052677229148">"Copier vers..."</string> <string name="menu_move" msgid="1828090633118079817">"Déplacer dans…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nouvelle fenêtre"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copier"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Coller"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Copier"</string> <string name="button_move" msgid="2202666023104202232">"Déplacer"</string> <string name="button_dismiss" msgid="3714065566893946085">"Faire disparaître"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Réessayer"</string> <string name="sort_name" msgid="9183560467917256779">"Par nom"</string> <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string> <string name="sort_size" msgid="3350681319735474741">"Par taille"</string> diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml index 0512ab15ae18..9616f634348c 100644 --- a/packages/DocumentsUI/res/values-fr/strings.xml +++ b/packages/DocumentsUI/res/values-fr/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fichiers"</string> <string name="title_open" msgid="4353228937663917801">"Ouvrir à partir de"</string> <string name="title_save" msgid="2433679664882857999">"Enregistrer sous"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Créer un dossier"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Grille"</string> <string name="menu_list" msgid="7279285939892417279">"Liste"</string> <string name="menu_sort" msgid="7677740407158414452">"Trier par"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Tout sélectionner"</string> <string name="menu_copy" msgid="3612326052677229148">"Copier vers…"</string> <string name="menu_move" msgid="1828090633118079817">"Placer dans…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nouvelle fenêtre"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copier"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Coller"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string> diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml index a1cd614f417e..aebf3a7f6182 100644 --- a/packages/DocumentsUI/res/values-gl-rES/strings.xml +++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Ficheiros"</string> <string name="title_open" msgid="4353228937663917801">"Abrir desde"</string> <string name="title_save" msgid="2433679664882857999">"Gardar en"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Crear cartafol"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Vista de grade"</string> <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Seleccionar todo"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiar en…"</string> <string name="menu_move" msgid="1828090633118079817">"Mover a…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nova ventá"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Pegar"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Tentar de novo"</string> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificación"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string> diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml index 059fb2cb2efb..9694afa56de5 100644 --- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ફાઇલો"</string> <string name="title_open" msgid="4353228937663917801">"અહીંથી ખોલો"</string> <string name="title_save" msgid="2433679664882857999">"આમાં સાચવો"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ફોલ્ડર બનાવો"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ગ્રિડ દૃશ્ય"</string> <string name="menu_list" msgid="7279285939892417279">"સૂચિ દૃશ્ય"</string> <string name="menu_sort" msgid="7677740407158414452">"આ પ્રમાણે સૉર્ટ કરો"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"બધા પસંદ કરો"</string> <string name="menu_copy" msgid="3612326052677229148">"આના પર કૉપિ કરો…"</string> <string name="menu_move" msgid="1828090633118079817">"આમાં ખસેડો…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"નવી વિંડો"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"કૉપિ કરો"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"પેસ્ટ કરો"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"આંતરિક સ્ટોરેજ બતાવો"</string> diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml index 8e33a005f4cc..3ee3d8b821ff 100644 --- a/packages/DocumentsUI/res/values-hi/strings.xml +++ b/packages/DocumentsUI/res/values-hi/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"फ़ाइलें"</string> <string name="title_open" msgid="4353228937663917801">"यहां से खोलें"</string> <string name="title_save" msgid="2433679664882857999">"यहां सहेजें"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"फ़ोल्डर बनाएं"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ग्रिड दृश्य"</string> <string name="menu_list" msgid="7279285939892417279">"सूची दृश्य"</string> <string name="menu_sort" msgid="7677740407158414452">"इससे क्रमित करें"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"सभी चुनें"</string> <string name="menu_copy" msgid="3612326052677229148">"इनकी कॉपी बनाएं..."</string> <string name="menu_move" msgid="1828090633118079817">"इसमें ले जाएं…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"नई विंडो"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"कॉपी करें"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"चिपकाएं"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आंतरिक मेमोरी दिखाएं"</string> diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml index 4774753aaf60..9d4393ee524f 100644 --- a/packages/DocumentsUI/res/values-hr/strings.xml +++ b/packages/DocumentsUI/res/values-hr/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Datoteke"</string> <string name="title_open" msgid="4353228937663917801">"Otvori iz"</string> <string name="title_save" msgid="2433679664882857999">"Spremi u"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Izradi mapu"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Prikaz rešetke"</string> <string name="menu_list" msgid="7279285939892417279">"Prikaz popisa"</string> <string name="menu_sort" msgid="7677740407158414452">"Poredano po"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Odaberi sve"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiraj u…"</string> <string name="menu_move" msgid="1828090633118079817">"Premjesti u…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Novi prozor"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiraj"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Zalijepi"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži internu pohranu"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string> <string name="button_move" msgid="2202666023104202232">"Premjesti"</string> <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Pokušaj ponovo"</string> <string name="sort_name" msgid="9183560467917256779">"Po nazivu"</string> <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string> <string name="sort_size" msgid="3350681319735474741">"Po veličini"</string> diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml index 7a521ecc3239..18dcd70b322e 100644 --- a/packages/DocumentsUI/res/values-hu/strings.xml +++ b/packages/DocumentsUI/res/values-hu/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fájlok"</string> <string name="title_open" msgid="4353228937663917801">"Megnyitás innen"</string> <string name="title_save" msgid="2433679664882857999">"Mentés ide"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Mappa létrehozása"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Rács"</string> <string name="menu_list" msgid="7279285939892417279">"Lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Rendezés"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Összes kijelölése"</string> <string name="menu_copy" msgid="3612326052677229148">"Másolás ide…"</string> <string name="menu_move" msgid="1828090633118079817">"Áthelyezés…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Új ablak"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Másolás"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Beillesztés"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Belső tárhely"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Másolás"</string> <string name="button_move" msgid="2202666023104202232">"Áthelyezés"</string> <string name="button_dismiss" msgid="3714065566893946085">"Elvetés"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Újrapróbálkozás"</string> <string name="sort_name" msgid="9183560467917256779">"Név szerint"</string> <string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string> <string name="sort_size" msgid="3350681319735474741">"Méret szerint"</string> diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml index 95d73f0e5b2e..67d7f6a3ea7a 100644 --- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml +++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Ֆայլեր"</string> <string name="title_open" msgid="4353228937663917801">"Բացել այստեղից"</string> <string name="title_save" msgid="2433679664882857999">"Պահել այստեղ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Ստեղծել պանակ"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Ցանցի տեսքով"</string> <string name="menu_list" msgid="7279285939892417279">"Ցուցակի տեսք"</string> <string name="menu_sort" msgid="7677740407158414452">"Դասավորել ըստ"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Ընտրել բոլորը"</string> <string name="menu_copy" msgid="3612326052677229148">"Պատճենել…"</string> <string name="menu_move" msgid="1828090633118079817">"Տեղափոխում դեպի…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Նոր պատուհան"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Պատճենել"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Տեղադրել"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ցույց տալ ներքին պահոցը"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Պատճենել"</string> <string name="button_move" msgid="2202666023104202232">"Տեղափոխել"</string> <string name="button_dismiss" msgid="3714065566893946085">"Փակել"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Փորձել նորից"</string> <string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string> <string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string> <string name="sort_size" msgid="3350681319735474741">"Ըստ չափի"</string> diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml index 63d415cadf46..a6f69bdf07b8 100644 --- a/packages/DocumentsUI/res/values-in/strings.xml +++ b/packages/DocumentsUI/res/values-in/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"File"</string> <string name="title_open" msgid="4353228937663917801">"Buka dari"</string> <string name="title_save" msgid="2433679664882857999">"Simpan ke"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Buat folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Tampilan kisi"</string> <string name="menu_list" msgid="7279285939892417279">"Tampilan daftar"</string> <string name="menu_sort" msgid="7677740407158414452">"Urutkan menurut"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Pilih semua"</string> <string name="menu_copy" msgid="3612326052677229148">"Salin ke…"</string> <string name="menu_move" msgid="1828090633118079817">"Pindahkan ke..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Jendela baru"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Salin"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Tempel"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Tampilkan simpanan internal"</string> diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml index 0c0e47fd4716..89d2e03824f4 100644 --- a/packages/DocumentsUI/res/values-is-rIS/strings.xml +++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Skrár"</string> <string name="title_open" msgid="4353228937663917801">"Opna frá"</string> <string name="title_save" msgid="2433679664882857999">"Vista í"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Búa til möppu"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Töfluyfirlit"</string> <string name="menu_list" msgid="7279285939892417279">"Listayfirlit"</string> <string name="menu_sort" msgid="7677740407158414452">"Raða eftir"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Velja allt"</string> <string name="menu_copy" msgid="3612326052677229148">"Afrita í ..."</string> <string name="menu_move" msgid="1828090633118079817">"Færa í…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nýr gluggi"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Afrita"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Líma"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Sýna innbyggða geymslu"</string> diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml index de129a7ec0cf..02a111ef0799 100644 --- a/packages/DocumentsUI/res/values-it/strings.xml +++ b/packages/DocumentsUI/res/values-it/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"File"</string> <string name="title_open" msgid="4353228937663917801">"Apri da"</string> <string name="title_save" msgid="2433679664882857999">"Salva in"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Crea cartella"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Visualizzazione griglia"</string> <string name="menu_list" msgid="7279285939892417279">"Visualizzazione elenco"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordina per"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Seleziona tutto"</string> <string name="menu_copy" msgid="3612326052677229148">"Copia in…"</string> <string name="menu_move" msgid="1828090633118079817">"Sposta in..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nuova finestra"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copia"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Incolla"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra memoria interna"</string> diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml index dbe463080c82..3d3c48989138 100644 --- a/packages/DocumentsUI/res/values-iw/strings.xml +++ b/packages/DocumentsUI/res/values-iw/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"קבצים"</string> <string name="title_open" msgid="4353228937663917801">"פתח מ-"</string> <string name="title_save" msgid="2433679664882857999">"שמור ב-"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"צור תיקיה"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"תצוגת רשת"</string> <string name="menu_list" msgid="7279285939892417279">"תצוגת רשימה"</string> <string name="menu_sort" msgid="7677740407158414452">"מיין לפי"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"בחר הכל"</string> <string name="menu_copy" msgid="3612326052677229148">"העתק אל…"</string> <string name="menu_move" msgid="1828090633118079817">"העברה אל…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"חלון חדש"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"העתק"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"הדבק"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"הצג אחסון פנימי"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"העתק"</string> <string name="button_move" msgid="2202666023104202232">"העבר"</string> <string name="button_dismiss" msgid="3714065566893946085">"הסר"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"נסה שוב"</string> <string name="sort_name" msgid="9183560467917256779">"לפי שם"</string> <string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string> <string name="sort_size" msgid="3350681319735474741">"לפי גודל"</string> diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml index 45f0ea1df6f8..a58c0a524256 100644 --- a/packages/DocumentsUI/res/values-ja/strings.xml +++ b/packages/DocumentsUI/res/values-ja/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ファイル"</string> <string name="title_open" msgid="4353228937663917801">"次から開く:"</string> <string name="title_save" msgid="2433679664882857999">"次に保存:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"フォルダを作成"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"グリッド表示"</string> <string name="menu_list" msgid="7279285939892417279">"リスト表示"</string> <string name="menu_sort" msgid="7677740407158414452">"並べ替え"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"すべて選択"</string> <string name="menu_copy" msgid="3612326052677229148">"コピー…"</string> <string name="menu_move" msgid="1828090633118079817">"移動..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"新しいウィンドウ"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"コピー"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"貼り付け"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"内部ストレージを表示"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"コピー"</string> <string name="button_move" msgid="2202666023104202232">"移動"</string> <string name="button_dismiss" msgid="3714065566893946085">"表示しない"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"再試行"</string> <string name="sort_name" msgid="9183560467917256779">"名前順"</string> <string name="sort_date" msgid="586080032956151448">"更新日順"</string> <string name="sort_size" msgid="3350681319735474741">"サイズ順"</string> diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml index 114e73c75cb5..cf4b5d64c3d6 100644 --- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml +++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ფაილები"</string> <string name="title_open" msgid="4353228937663917801">"გახსნა აქედან:"</string> <string name="title_save" msgid="2433679664882857999">"შენახვა აქ:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"საქაღალდის შექმნა"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ბადის ხედი"</string> <string name="menu_list" msgid="7279285939892417279">"სიის ხედი"</string> <string name="menu_sort" msgid="7677740407158414452">"სორტირება:"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"ყველას არჩევა"</string> <string name="menu_copy" msgid="3612326052677229148">"კოპირება…"</string> <string name="menu_move" msgid="1828090633118079817">"გადაადგილება..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"ახალი ფანჯარა"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"კოპირება"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ჩასმა"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"შიდა საცავის ჩვენება"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"კოპირება"</string> <string name="button_move" msgid="2202666023104202232">"გადაადგილება"</string> <string name="button_dismiss" msgid="3714065566893946085">"დახურვა"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"ისევ ცდა"</string> <string name="sort_name" msgid="9183560467917256779">"სახელით"</string> <string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string> <string name="sort_size" msgid="3350681319735474741">"ზომით"</string> diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml index af123c62b20c..5ec16a9ee729 100644 --- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml +++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Файлдар"</string> <string name="title_open" msgid="4353228937663917801">"Мынадан ашу:"</string> <string name="title_save" msgid="2433679664882857999">"Сақталатын орны"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Қалта жасақтау"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Торлы көрініс"</string> <string name="menu_list" msgid="7279285939892417279">"Тізім көрінісі"</string> <string name="menu_sort" msgid="7677740407158414452">"Белгіге қарай сұрыптау"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Барлығын таңдау"</string> <string name="menu_copy" msgid="3612326052677229148">"Көшіру орны…"</string> <string name="menu_move" msgid="1828090633118079817">"Орнын ауыстыру…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Жаңа терезе"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Көшіру"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Қою"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ішкі жадты көрсету"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Көшіру"</string> <string name="button_move" msgid="2202666023104202232">"Жылжыту"</string> <string name="button_dismiss" msgid="3714065566893946085">"Өшіру"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Әрекетті қайталау"</string> <string name="sort_name" msgid="9183560467917256779">"Атауы бойынша"</string> <string name="sort_date" msgid="586080032956151448">"Өзгертілген мерзімі бойынша"</string> <string name="sort_size" msgid="3350681319735474741">"Өлшемі бойынша"</string> diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml index 8f3feaedefd1..73778823b708 100644 --- a/packages/DocumentsUI/res/values-km-rKH/strings.xml +++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ឯកសារ"</string> <string name="title_open" msgid="4353228937663917801">"បើកពី"</string> <string name="title_save" msgid="2433679664882857999">"រក្សាទុកទៅ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"បង្កើតថត"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ទិដ្ឋភាពក្រឡា"</string> <string name="menu_list" msgid="7279285939892417279">"ទិដ្ឋភាពបញ្ជី"</string> <string name="menu_sort" msgid="7677740407158414452">"តម្រៀបតាម"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"ជ្រើសរើសទាំងអស់"</string> <string name="menu_copy" msgid="3612326052677229148">"ថតចម្លងទៅ…"</string> <string name="menu_move" msgid="1828090633118079817">"ផ្លាស់ទីទៅ៖"</string> + <string name="menu_new_window" msgid="1226032889278727538">"បង្អួចថ្មី"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ចម្លង"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"បិទភ្ជាប់"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"បង្ហាញឧបករណ៍ផ្ទុកខាងក្នុង"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"ចម្លង"</string> <string name="button_move" msgid="2202666023104202232">"ផ្លាស់ទី"</string> <string name="button_dismiss" msgid="3714065566893946085">"បដិសេធ"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"ព្យាយាមម្ដងទៀត"</string> <string name="sort_name" msgid="9183560467917256779">"តាមឈ្មោះ"</string> <string name="sort_date" msgid="586080032956151448">"តាមកាលបរិច្ឆេទបានកែប្រែ"</string> <string name="sort_size" msgid="3350681319735474741">"តាមទំហំ"</string> diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml index 826cf1e3fa73..a5cad7bd1003 100644 --- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ಫೈಲ್ಗಳು"</string> <string name="title_open" msgid="4353228937663917801">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string> <string name="title_save" msgid="2433679664882857999">"ಇವುಗಳಲ್ಲಿ ಉಳಿಸಿ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ಫೋಲ್ಡರ್ ರಚಿಸು"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ಗ್ರಿಡ್ ವೀಕ್ಷಣೆ"</string> <string name="menu_list" msgid="7279285939892417279">"ಪಟ್ಟಿ ವೀಕ್ಷಣೆ"</string> <string name="menu_sort" msgid="7677740407158414452">"ಈ ಪ್ರಕಾರ ವಿಂಗಡಿಸು"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"ಎಲ್ಲವನ್ನೂ ಆಯ್ಕೆಮಾಡಿ"</string> <string name="menu_copy" msgid="3612326052677229148">"ಇದಕ್ಕೆ ನಕಲಿಸಿ…"</string> <string name="menu_move" msgid="1828090633118079817">"ಇದಕ್ಕೆ ಸರಿಸು…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"ಹೊಸ ವಿಂಡೋ"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ನಕಲಿಸು"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ಅಂಟಿಸು"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯನ್ನು ತೋರಿಸು"</string> diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml index 322b43b3bc3a..1426bf8225cb 100644 --- a/packages/DocumentsUI/res/values-ko/strings.xml +++ b/packages/DocumentsUI/res/values-ko/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"파일"</string> <string name="title_open" msgid="4353228937663917801">"열기:"</string> <string name="title_save" msgid="2433679664882857999">"저장 위치:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"폴더 만들기"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"바둑판식 보기"</string> <string name="menu_list" msgid="7279285939892417279">"목록 보기"</string> <string name="menu_sort" msgid="7677740407158414452">"정렬 기준"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"모두 선택"</string> <string name="menu_copy" msgid="3612326052677229148">"복사…"</string> <string name="menu_move" msgid="1828090633118079817">"이동…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"새 창"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"복사"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"붙여넣기"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"내부 저장소 표시"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"복사"</string> <string name="button_move" msgid="2202666023104202232">"이동"</string> <string name="button_dismiss" msgid="3714065566893946085">"닫기"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"다시 시도"</string> <string name="sort_name" msgid="9183560467917256779">"이름순"</string> <string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string> <string name="sort_size" msgid="3350681319735474741">"크기순"</string> diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml index c8aa69eb3c18..c1eadb76f682 100644 --- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml +++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Файлдар"</string> <string name="title_open" msgid="4353228937663917801">"Кийинкиден ачуу:"</string> <string name="title_save" msgid="2433679664882857999">"Кийинкиге сактоо:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Папка түзүү"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Тор көрүнүшү"</string> <string name="menu_list" msgid="7279285939892417279">"Тизмек көрүнүшү"</string> <string name="menu_sort" msgid="7677740407158414452">"Ылгоо"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Бардыгын тандоо"</string> <string name="menu_copy" msgid="3612326052677229148">"Төмөнкүгө көчүрүү…"</string> <string name="menu_move" msgid="1828090633118079817">"Төмөнкүгө жылдыруу..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Жаңы терезе"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Көчүрүү"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Чаптоо"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ички сактагычты көрсөтүү"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Көчүрүү"</string> <string name="button_move" msgid="2202666023104202232">"Жылдыруу"</string> <string name="button_dismiss" msgid="3714065566893946085">"Этибарга албоо"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Дагы аракет кылыңыз"</string> <string name="sort_name" msgid="9183560467917256779">"Аты боюнча"</string> <string name="sort_date" msgid="586080032956151448">"Өзгөртүлгөн күнү боюнча"</string> <string name="sort_size" msgid="3350681319735474741">"Өлчөмү боюнча"</string> diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml index dedfa0552b36..5c0ffdb6e401 100644 --- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml +++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ໄຟລ໌"</string> <string name="title_open" msgid="4353228937663917801">"ເປີດຈາກ"</string> <string name="title_save" msgid="2433679664882857999">"ບັນທຶກໄປທີ່"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ສ້າງໂຟນເດີ"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ມຸມມອງແບບຊ່ອງ"</string> <string name="menu_list" msgid="7279285939892417279">"ມຸມມອງແບບລາຍຊື່"</string> <string name="menu_sort" msgid="7677740407158414452">"ຮຽງລຳດັບຕາມ"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"ເລືອກທັງຫມົດ"</string> <string name="menu_copy" msgid="3612326052677229148">"ອັດສຳເນົາໃສ່…"</string> <string name="menu_move" msgid="1828090633118079817">"ຍ້າຍໄປໃສ່..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"ໜ້າຈໍໃໝ່"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ສຳເນົາ"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ວາງໃສ່"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ສະແດງໂຕເກັບຂໍ້ມູນພາຍໃນ"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"ສຳເນົາ"</string> <string name="button_move" msgid="2202666023104202232">"ຍ້າຍ"</string> <string name="button_dismiss" msgid="3714065566893946085">"ປິດໄວ້"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"ລອງໃໝ່ອີກ"</string> <string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string> <string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string> <string name="sort_size" msgid="3350681319735474741">"ຕາມຂະໜາດ"</string> diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml index 0c8b44388e00..49774e8c1366 100644 --- a/packages/DocumentsUI/res/values-lt/strings.xml +++ b/packages/DocumentsUI/res/values-lt/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Failai"</string> <string name="title_open" msgid="4353228937663917801">"Atidaryti iš"</string> <string name="title_save" msgid="2433679664882857999">"Išsaugoti į"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Kurti aplanką"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Tinklelio rodinys"</string> <string name="menu_list" msgid="7279285939892417279">"Sąrašo rodinys"</string> <string name="menu_sort" msgid="7677740407158414452">"Rūšiuoti pagal"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Pasirinkti viską"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopijuoti į..."</string> <string name="menu_move" msgid="1828090633118079817">"Perkelti į…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Naujas langas"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopijuoti"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Įklijuoti"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rodyti vidinę atmintį"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopijuoti"</string> <string name="button_move" msgid="2202666023104202232">"Perkelti"</string> <string name="button_dismiss" msgid="3714065566893946085">"Atsisakyti"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Bandyti dar kartą"</string> <string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string> <string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string> <string name="sort_size" msgid="3350681319735474741">"Pagal dydį"</string> diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml index 5c79554424f7..9cb34250d2c7 100644 --- a/packages/DocumentsUI/res/values-lv/strings.xml +++ b/packages/DocumentsUI/res/values-lv/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Faili"</string> <string name="title_open" msgid="4353228937663917801">"Atvēršana no:"</string> <string name="title_save" msgid="2433679664882857999">"Saglabāšana:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Izveidot mapi"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Režģis"</string> <string name="menu_list" msgid="7279285939892417279">"Saraksts"</string> <string name="menu_sort" msgid="7677740407158414452">"Kārtot pēc"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Atlasīt visus"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopēt…"</string> <string name="menu_move" msgid="1828090633118079817">"Pārvietot uz…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Jauns logs"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopēt"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Ielīmēt"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rādīt iekšējo atmiņu"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopēt"</string> <string name="button_move" msgid="2202666023104202232">"Pārvietot"</string> <string name="button_dismiss" msgid="3714065566893946085">"Noraidīt"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Mēģināt vēlreiz"</string> <string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string> <string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string> <string name="sort_size" msgid="3350681319735474741">"Pēc lieluma"</string> diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml index b2cb9f1ca2ea..149d0d43ee9a 100644 --- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml +++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Датотеки"</string> <string name="title_open" msgid="4353228937663917801">"Отвори од"</string> <string name="title_save" msgid="2433679664882857999">"Зачувај во"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Создади папка"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Приказ на мрежа"</string> <string name="menu_list" msgid="7279285939892417279">"Приказ на список"</string> <string name="menu_sort" msgid="7677740407158414452">"Подреди по"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Избери ги сите"</string> <string name="menu_copy" msgid="3612326052677229148">"Копирај во…"</string> <string name="menu_move" msgid="1828090633118079817">"Премести во..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Нов прозорец"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копирај"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Залепи"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи внатрешна мемор."</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Копирај"</string> <string name="button_move" msgid="2202666023104202232">"Премести"</string> <string name="button_dismiss" msgid="3714065566893946085">"Отфрли"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Обиди се пак"</string> <string name="sort_name" msgid="9183560467917256779">"По име"</string> <string name="sort_date" msgid="586080032956151448">"Изменети по датум"</string> <string name="sort_size" msgid="3350681319735474741">"По големина"</string> diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml index 07efa66bc871..c621359a93d0 100644 --- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ഫയലുകൾ"</string> <string name="title_open" msgid="4353228937663917801">"ഇതിൽ നിന്നും തുറക്കുക"</string> <string name="title_save" msgid="2433679664882857999">"ഇതില് സംരക്ഷിക്കുക"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ഫോൾഡർ സൃഷ്ടിക്കുക"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ഗ്രിഡ് കാഴ്ച"</string> <string name="menu_list" msgid="7279285939892417279">"ലിസ്റ്റ് കാഴ്ച"</string> <string name="menu_sort" msgid="7677740407158414452">"ഇപ്രകാരം അടുക്കുക"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"എല്ലാം തിരഞ്ഞെടുക്കുക"</string> <string name="menu_copy" msgid="3612326052677229148">"ഇതിൽ പകർത്തുക…"</string> <string name="menu_move" msgid="1828090633118079817">"ഇതിലേക്ക് നീക്കുക..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"പുതിയ വിന്ഡോ"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"പകര്ത്തുക"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ഒട്ടിക്കുക"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ആന്തരിക സ്റ്റോറേജ് കാണിക്കുക"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"പകര്ത്തുക"</string> <string name="button_move" msgid="2202666023104202232">"നീക്കുക"</string> <string name="button_dismiss" msgid="3714065566893946085">"ഡിസ്മിസ് ചെയ്യുക"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"വീണ്ടും ശ്രമിക്കുക"</string> <string name="sort_name" msgid="9183560467917256779">"പേര് പ്രകാരം"</string> <string name="sort_date" msgid="586080032956151448">"പരിഷ്ക്കരിച്ച തീയതി പ്രകാരം"</string> <string name="sort_size" msgid="3350681319735474741">"വലുപ്പം പ്രകാരം"</string> diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml index d45778cab5bd..fb7503e87bd0 100644 --- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml +++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Файл"</string> <string name="title_open" msgid="4353228937663917801">"Нээх"</string> <string name="title_save" msgid="2433679664882857999">"Хадгалах"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Фолдер үүсгэх"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Эгнүүлж харах"</string> <string name="menu_list" msgid="7279285939892417279">"Жагсааж харах"</string> <string name="menu_sort" msgid="7677740407158414452">"Эрэмбэлэх"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Бүгдийг сонгох"</string> <string name="menu_copy" msgid="3612326052677229148">"...руу хуулах"</string> <string name="menu_move" msgid="1828090633118079817">"Байршуулах газар"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Шинэ цонх"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Хуулах"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Буулгах"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Дотоод санг харуулах"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Хуулах"</string> <string name="button_move" msgid="2202666023104202232">"Зөөх"</string> <string name="button_dismiss" msgid="3714065566893946085">"Алгасах"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Дахин оролдоно уу"</string> <string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string> <string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string> <string name="sort_size" msgid="3350681319735474741">"Хэмжээгээр"</string> diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml index 8d70143ffc0a..8d5885a7466f 100644 --- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"फायली"</string> <string name="title_open" msgid="4353228937663917801">"वरून उघडा"</string> <string name="title_save" msgid="2433679664882857999">"येथे जतन करा"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"फोल्डर तयार करा"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ग्रिड दृश्य"</string> <string name="menu_list" msgid="7279285939892417279">"सूची"</string> <string name="menu_sort" msgid="7677740407158414452">"नुसार क्रमवारी लावा"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"सर्व निवडा"</string> <string name="menu_copy" msgid="3612326052677229148">"यावर कॉपी करा…"</string> <string name="menu_move" msgid="1828090633118079817">"यावर हलवा…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"नवीन विंडो"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"कॉपी करा"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"पेस्ट करा"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"अंतर्गत संचयन दर्शवा"</string> diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml index 22501095b614..6904e1074b6a 100644 --- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml +++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fail"</string> <string name="title_open" msgid="4353228937663917801">"Buka dari"</string> <string name="title_save" msgid="2433679664882857999">"Simpan ke"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Buat folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Paparan grid"</string> <string name="menu_list" msgid="7279285939892417279">"Paparan senarai"</string> <string name="menu_sort" msgid="7677740407158414452">"Isih mengikut"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Pilih semua"</string> <string name="menu_copy" msgid="3612326052677229148">"Salin ke..."</string> <string name="menu_move" msgid="1828090633118079817">"Alihkan ke…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Tetingkap baharu"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Salin"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Tampal"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Papar storan dalaman"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Salin"</string> <string name="button_move" msgid="2202666023104202232">"Alihkan"</string> <string name="button_dismiss" msgid="3714065566893946085">"Tolak"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Cuba Lagi"</string> <string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string> <string name="sort_date" msgid="586080032956151448">"Mengikut tarikh diubah"</string> <string name="sort_size" msgid="3350681319735474741">"Mengikut saiz"</string> diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml index 480c27b1ddfb..f3ed0f7c2823 100644 --- a/packages/DocumentsUI/res/values-my-rMM/strings.xml +++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ဖိုင်များ"</string> <string name="title_open" msgid="4353228937663917801">"မှ ဖွင့်ပါ"</string> <string name="title_save" msgid="2433679664882857999">"သို့ သိမ်းပါ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"အကန့် တည်ဆောက်ရန်"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ဖယားကွက်မြင်ကွင်း"</string> <string name="menu_list" msgid="7279285939892417279">"အစဉ်လိုက်မြင်ကွင်း"</string> <string name="menu_sort" msgid="7677740407158414452">"အစဉ်အလိုက် စီခြင်း"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"အားလုံးကို ရွေးရန်"</string> <string name="menu_copy" msgid="3612326052677229148">"သို့ကူးယူရန်…"</string> <string name="menu_move" msgid="1828090633118079817">"...သို့ ရွှေ့ရန်"</string> + <string name="menu_new_window" msgid="1226032889278727538">"ဝင်းဒိုးသစ်"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ကူးယူရန်"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ကပ်ရန်"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"စက်ရှိစတိုရုံ ပြပါ"</string> diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml index 48355aab72ba..5f71805efb07 100644 --- a/packages/DocumentsUI/res/values-nb/strings.xml +++ b/packages/DocumentsUI/res/values-nb/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Filer"</string> <string name="title_open" msgid="4353228937663917801">"Åpne fra"</string> <string name="title_save" msgid="2433679664882857999">"Lagre i"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Opprett en mappe"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Rutenettvisning"</string> <string name="menu_list" msgid="7279285939892417279">"Listevisning"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortér etter"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Markér alt"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiér til …"</string> <string name="menu_move" msgid="1828090633118079817">"Flytt til"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nytt vindu"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiér"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Lim inn"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis den interne lagringen"</string> diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml index 53942c192ac3..1bc6a292fe6a 100644 --- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml +++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"फाइलहरू"</string> <string name="title_open" msgid="4353228937663917801">"यसबाट खोल्नुहोस्"</string> <string name="title_save" msgid="2433679664882857999">"यसमा सुरक्षित गर्नुहोस्"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"फोल्डर सिर्जना गर्नुहोस्"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ग्रिड दृश्य"</string> <string name="menu_list" msgid="7279285939892417279">"सूची दृश्य"</string> <string name="menu_sort" msgid="7677740407158414452">"यसद्वारा क्रमवद्घ गर्नुहोस्"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"सबै चयन गर्नुहोस्"</string> <string name="menu_copy" msgid="3612326052677229148">"यसमा प्रतिलिपि गर्नुहोस् ..."</string> <string name="menu_move" msgid="1828090633118079817">"…मा सार्नुहोस्"</string> + <string name="menu_new_window" msgid="1226032889278727538">"नयाँ विन्डो"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"प्रतिलिपि बनाउनुहोस्"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"टाँस्नुहोस्"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आन्तरिक भण्डारण देखाउनुहोस्"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"प्रतिलिपि बनाउनुहोस्"</string> <string name="button_move" msgid="2202666023104202232">"सार्नुहोस्"</string> <string name="button_dismiss" msgid="3714065566893946085">"खारेज गर्नुहोस्"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"पुन: प्रयास गर्नुहोस्"</string> <string name="sort_name" msgid="9183560467917256779">"नाम अनुसार"</string> <string name="sort_date" msgid="586080032956151448">"परिमार्जित मिति अनुसार"</string> <string name="sort_size" msgid="3350681319735474741">"आकार अनुसार"</string> diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml index d3e6bbe9cae2..79a6de9fd863 100644 --- a/packages/DocumentsUI/res/values-nl/strings.xml +++ b/packages/DocumentsUI/res/values-nl/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Bestanden"</string> <string name="title_open" msgid="4353228937663917801">"Openen vanuit"</string> <string name="title_save" msgid="2433679664882857999">"Opslaan in"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Map maken"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Rasterweergave"</string> <string name="menu_list" msgid="7279285939892417279">"Lijstweergave"</string> <string name="menu_sort" msgid="7677740407158414452">"Sorteren op"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Alles selecteren"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiëren naar…"</string> <string name="menu_move" msgid="1828090633118079817">"Verplaatsen naar…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nieuw venster"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiëren"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Plakken"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Interne opslag weergeven"</string> diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml index 3b1439653708..c4fe4e4f2789 100644 --- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ਫਾਈਲਾਂ"</string> <string name="title_open" msgid="4353228937663917801">"ਤੋਂ ਖੋਲ੍ਹੋ"</string> <string name="title_save" msgid="2433679664882857999">"ਇਸ ਵਿੱਚ ਸੁਰੱਖਿਅਤ ਕਰੋ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ਫੋਲਡਰ ਬਣਾਓ"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ਗ੍ਰਿਡ ਵਿਊ"</string> <string name="menu_list" msgid="7279285939892417279">"ਸੂਚੀ ਦ੍ਰਿਸ਼"</string> <string name="menu_sort" msgid="7677740407158414452">"ਇਸ ਅਨੁਸਾਰ ਛਾਂਟੋ"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"ਸਾਰੇ ਚੁਣੋ"</string> <string name="menu_copy" msgid="3612326052677229148">"ਇਸ ਵਿੱਚ ਕਾਪੀ ਕਰੋ…"</string> <string name="menu_move" msgid="1828090633118079817">"ਇਸ ਵਿੱਚ ਮੂਵ ਕਰੋ..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"ਨਵੀਂ ਵਿੰਡੋ"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ਕਾਪੀ ਕਰੋ"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ਪੇਸਟ ਕਰੋ"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ ਦਿਖਾਓ"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"ਕਾਪੀ ਕਰੋ"</string> <string name="button_move" msgid="2202666023104202232">"ਮੂਵ ਕਰੋ"</string> <string name="button_dismiss" msgid="3714065566893946085">"ਬਰਖਾਸਤ ਕਰੋ"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> <string name="sort_name" msgid="9183560467917256779">"ਨਾਮ ਮੁਤਾਬਕ"</string> <string name="sort_date" msgid="586080032956151448">"ਤਾਰੀਖ ਮੁਤਾਬਕ ਸੰਸ਼ੋਧਿਤ"</string> <string name="sort_size" msgid="3350681319735474741">"ਆਕਾਰ ਮੁਤਾਬਕ"</string> diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml index 3e4ef6837726..30b0806574ea 100644 --- a/packages/DocumentsUI/res/values-pl/strings.xml +++ b/packages/DocumentsUI/res/values-pl/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Pliki"</string> <string name="title_open" msgid="4353228937663917801">"Otwórz z"</string> <string name="title_save" msgid="2433679664882857999">"Zapisz w"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Utwórz folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Widok siatki"</string> <string name="menu_list" msgid="7279285939892417279">"Widok listy"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortuj według"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Zaznacz wszystko"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiuj do…"</string> <string name="menu_move" msgid="1828090633118079817">"Przenieś do…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nowe okno"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiuj"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Wklej"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaż pamięć wewnętrzną"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopiuj"</string> <string name="button_move" msgid="2202666023104202232">"Przenieś"</string> <string name="button_dismiss" msgid="3714065566893946085">"Zamknij"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Spróbuj ponownie"</string> <string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string> <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string> <string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string> diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml index ca984cffe69d..0233e3d7abd5 100644 --- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml +++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Arquivos"</string> <string name="title_open" msgid="4353228937663917801">"Abrir de"</string> <string name="title_save" msgid="2433679664882857999">"Salvar em"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Criar pasta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Visualização em grade"</string> <string name="menu_list" msgid="7279285939892417279">"Visualização em lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Classificar por"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Selecionar tudo"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiar para..."</string> <string name="menu_move" msgid="1828090633118079817">"Mover para..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nova janela"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Colar"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar armaz. interno"</string> diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml index ab673580ba19..0c41a9152ada 100644 --- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml +++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Ficheiros"</string> <string name="title_open" msgid="4353228937663917801">"Abrir de"</string> <string name="title_save" msgid="2433679664882857999">"Guardar em"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Criar pasta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Vista de grelha"</string> <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Selecionar tudo"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiar para…"</string> <string name="menu_move" msgid="1828090633118079817">"Mover para..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nova janela"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Colar"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar mem. armaz. int."</string> diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml index ca984cffe69d..0233e3d7abd5 100644 --- a/packages/DocumentsUI/res/values-pt/strings.xml +++ b/packages/DocumentsUI/res/values-pt/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Arquivos"</string> <string name="title_open" msgid="4353228937663917801">"Abrir de"</string> <string name="title_save" msgid="2433679664882857999">"Salvar em"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Criar pasta"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Visualização em grade"</string> <string name="menu_list" msgid="7279285939892417279">"Visualização em lista"</string> <string name="menu_sort" msgid="7677740407158414452">"Classificar por"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Selecionar tudo"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiar para..."</string> <string name="menu_move" msgid="1828090633118079817">"Mover para..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nova janela"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Colar"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar armaz. interno"</string> diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml index e927b785e2f7..27734d574351 100644 --- a/packages/DocumentsUI/res/values-ro/strings.xml +++ b/packages/DocumentsUI/res/values-ro/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fișiere"</string> <string name="title_open" msgid="4353228937663917801">"Deschideți din"</string> <string name="title_save" msgid="2433679664882857999">"Salvați în"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Creați un dosar"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Afișare tip grilă"</string> <string name="menu_list" msgid="7279285939892417279">"Afișare tip listă"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortați după"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Selectați tot"</string> <string name="menu_copy" msgid="3612326052677229148">"Copiați în…"</string> <string name="menu_move" msgid="1828090633118079817">"Mutați în…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Fereastră nouă"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiați"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Inserați"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Afișați stocarea internă"</string> diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml index cdf20cadfc61..152992e2d13a 100644 --- a/packages/DocumentsUI/res/values-ru/strings.xml +++ b/packages/DocumentsUI/res/values-ru/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Файлы"</string> <string name="title_open" msgid="4353228937663917801">"Открыть"</string> <string name="title_save" msgid="2433679664882857999">"Сохранить"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Новая папка"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Сетка"</string> <string name="menu_list" msgid="7279285939892417279">"Список"</string> <string name="menu_sort" msgid="7677740407158414452">"Сортировать"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Выбрать все"</string> <string name="menu_copy" msgid="3612326052677229148">"Копировать в…"</string> <string name="menu_move" msgid="1828090633118079817">"Переместить"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Новое окно"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копировать"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Вставить"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Внутренняя память"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Копировать"</string> <string name="button_move" msgid="2202666023104202232">"Переместить"</string> <string name="button_dismiss" msgid="3714065566893946085">"Скрыть"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Повторить"</string> <string name="sort_name" msgid="9183560467917256779">"По названию"</string> <string name="sort_date" msgid="586080032956151448">"По дате изменения"</string> <string name="sort_size" msgid="3350681319735474741">"По размеру"</string> diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml index 138f8a6c6b76..a8165a1a91a0 100644 --- a/packages/DocumentsUI/res/values-si-rLK/strings.xml +++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ගොනු"</string> <string name="title_open" msgid="4353228937663917801">"විවෘත වන්නේ"</string> <string name="title_save" msgid="2433679664882857999">"සුරකින්නේ"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ෆෝල්ඩරයක් සාදන්න"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"ජාල පෙනුම"</string> <string name="menu_list" msgid="7279285939892417279">"ලැයිස්තු පෙනුම"</string> <string name="menu_sort" msgid="7677740407158414452">"අනුපිළිවෙලට සකසා ඇත්තේ"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"සියල්ල තෝරන්න"</string> <string name="menu_copy" msgid="3612326052677229148">"වෙත පිටපත් කරන්න..."</string> <string name="menu_move" msgid="1828090633118079817">"වෙත ගෙනයන්න..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"නව කවුළුව"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"පිටපත් කරන්න"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"අලවන්න"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"අභ්යන්තර ආචයනය පෙන්වන්න"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"පිටපත් කිරීම"</string> <string name="button_move" msgid="2202666023104202232">"ගෙන යන්න"</string> <string name="button_dismiss" msgid="3714065566893946085">"ඉවතලන්න"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"නැවත උත්සාහ කරන්න"</string> <string name="sort_name" msgid="9183560467917256779">"නමින්"</string> <string name="sort_date" msgid="586080032956151448">"වෙනස් කරන ලද දිනයෙන්"</string> <string name="sort_size" msgid="3350681319735474741">"ප්රමාණය මගින්"</string> diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml index 4310819f08a4..3441f26dad07 100644 --- a/packages/DocumentsUI/res/values-sk/strings.xml +++ b/packages/DocumentsUI/res/values-sk/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Súbory"</string> <string name="title_open" msgid="4353228937663917801">"Otvoriť z"</string> <string name="title_save" msgid="2433679664882857999">"Uložiť do"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Vytvoriť priečinok"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Zobrazenie mriežky"</string> <string name="menu_list" msgid="7279285939892417279">"Zobrazenie zoznamu"</string> <string name="menu_sort" msgid="7677740407158414452">"Zoradiť podľa"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Vybrať všetko"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopírovať do…"</string> <string name="menu_move" msgid="1828090633118079817">"Presunúť do…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nové okno"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopírovať"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Prilepiť"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobraziť interné úložisko"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopírovať"</string> <string name="button_move" msgid="2202666023104202232">"Presunúť"</string> <string name="button_dismiss" msgid="3714065566893946085">"Odmietnuť"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Skúsiť znova"</string> <string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string> <string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string> <string name="sort_size" msgid="3350681319735474741">"Podľa veľkosti"</string> diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml index c9982a7a0233..fe366641e783 100644 --- a/packages/DocumentsUI/res/values-sl/strings.xml +++ b/packages/DocumentsUI/res/values-sl/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Datoteke"</string> <string name="title_open" msgid="4353228937663917801">"Odpri iz mape"</string> <string name="title_save" msgid="2433679664882857999">"Shrani v"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Ustvarjanje mape"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Mrežni pogled"</string> <string name="menu_list" msgid="7279285939892417279">"Pogled seznama"</string> <string name="menu_sort" msgid="7677740407158414452">"Razvrsti glede na"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Izberi vse"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiraj v …"</string> <string name="menu_move" msgid="1828090633118079817">"Premakni v ..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Novo okno"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiraj"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Prilepi"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži notranjo shrambo"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string> <string name="button_move" msgid="2202666023104202232">"Premik"</string> <string name="button_dismiss" msgid="3714065566893946085">"Opusti"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Poskusite znova"</string> <string name="sort_name" msgid="9183560467917256779">"Po imenu"</string> <string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string> <string name="sort_size" msgid="3350681319735474741">"Po velikosti"</string> diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml index f1ee1bca33eb..18794f589910 100644 --- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml +++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Skedarët"</string> <string name="title_open" msgid="4353228937663917801">"Hap nga"</string> <string name="title_save" msgid="2433679664882857999">"Ruaje te"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Krijo dosje"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Pamje rrjete"</string> <string name="menu_list" msgid="7279285939892417279">"Pamje liste"</string> <string name="menu_sort" msgid="7677740407158414452">"Rendit sipas"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Zgjidhi të gjitha"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopjo te..."</string> <string name="menu_move" msgid="1828090633118079817">"Zhvendos te..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Dritare e re"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopjo"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Ngjit"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Trego hapësirën e brendshme ruajtëse"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopjo"</string> <string name="button_move" msgid="2202666023104202232">"Zhvendos"</string> <string name="button_dismiss" msgid="3714065566893946085">"Largoje"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Provo sërish"</string> <string name="sort_name" msgid="9183560467917256779">"Sipas emrit"</string> <string name="sort_date" msgid="586080032956151448">"Sipas datës së modifikimit"</string> <string name="sort_size" msgid="3350681319735474741">"Sipas madhësisë"</string> diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml index c5116c2f78a9..fa047f250b00 100644 --- a/packages/DocumentsUI/res/values-sr/strings.xml +++ b/packages/DocumentsUI/res/values-sr/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Датотеке"</string> <string name="title_open" msgid="4353228937663917801">"Отвори са"</string> <string name="title_save" msgid="2433679664882857999">"Сачувај у"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Направи директоријум"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Приказ мреже"</string> <string name="menu_list" msgid="7279285939892417279">"Приказ листе"</string> <string name="menu_sort" msgid="7677740407158414452">"Сортирај према"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Изабери све"</string> <string name="menu_copy" msgid="3612326052677229148">"Копирај на..."</string> <string name="menu_move" msgid="1828090633118079817">"Премести у..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Нови прозор"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копирај"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Налепи"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи интерну меморију"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Копирај"</string> <string name="button_move" msgid="2202666023104202232">"Премести"</string> <string name="button_dismiss" msgid="3714065566893946085">"Одбаци"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Покушај поново"</string> <string name="sort_name" msgid="9183560467917256779">"Према имену"</string> <string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string> <string name="sort_size" msgid="3350681319735474741">"Према величини"</string> diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml index 06e6514d8afb..5ac869179591 100644 --- a/packages/DocumentsUI/res/values-sv/strings.xml +++ b/packages/DocumentsUI/res/values-sv/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Filer"</string> <string name="title_open" msgid="4353228937663917801">"Öppna från"</string> <string name="title_save" msgid="2433679664882857999">"Spara till"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Skapa mapp"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Rutnätsvy"</string> <string name="menu_list" msgid="7279285939892417279">"Listvy"</string> <string name="menu_sort" msgid="7677740407158414452">"Sortera efter"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Markera allt"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopiera till …"</string> <string name="menu_move" msgid="1828090633118079817">"Flytta till ..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Nytt fönster"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiera"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Klistra in"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Visa internminne"</string> diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml index 79bae1f94cc8..3daa18e66892 100644 --- a/packages/DocumentsUI/res/values-sw/strings.xml +++ b/packages/DocumentsUI/res/values-sw/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Faili"</string> <string name="title_open" msgid="4353228937663917801">"Fungua kutoka"</string> <string name="title_save" msgid="2433679664882857999">"Hifadhi kwenye"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Unda folda"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Mwonekano gridi"</string> <string name="menu_list" msgid="7279285939892417279">"Mwonekano orodha"</string> <string name="menu_sort" msgid="7677740407158414452">"Panga kwa"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Chagua zote"</string> <string name="menu_copy" msgid="3612326052677229148">"Nakili kwenda..."</string> <string name="menu_move" msgid="1828090633118079817">"Hamisha hadi..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Dirisha jipya"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Nakili"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Bandika"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Onyesha hifadhi ya ndani"</string> diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml index 117aabce296e..14fa7020bd25 100644 --- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"கோப்புகள்"</string> <string name="title_open" msgid="4353228937663917801">"இதில் திற"</string> <string name="title_save" msgid="2433679664882857999">"இதில் சேமி"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"கோப்புறையை உருவாக்கு"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"கட்டக் காட்சி"</string> <string name="menu_list" msgid="7279285939892417279">"பட்டியல்"</string> <string name="menu_sort" msgid="7677740407158414452">"இதன்படி வரிசைப்படுத்து"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"எல்லாவற்றையும் தேர்ந்தெடு"</string> <string name="menu_copy" msgid="3612326052677229148">"இங்கு நகலெடு…"</string> <string name="menu_move" msgid="1828090633118079817">"இதற்கு நகர்த்து…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"புதிய சாளரம்"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"நகலெடு"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ஒட்டு"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"அகச் சேமிப்பகத்தைக் காட்டு"</string> diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml index 21b7f586c3d6..17c0066c441b 100644 --- a/packages/DocumentsUI/res/values-te-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ఫైల్లు"</string> <string name="title_open" msgid="4353228937663917801">"ఇక్కడి నుండి తెరువు"</string> <string name="title_save" msgid="2433679664882857999">"ఇందులో సేవ్ చేయి"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"ఫోల్డర్ను సృష్టించు"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"గ్రిడ్ వీక్షణ"</string> <string name="menu_list" msgid="7279285939892417279">"జాబితా వీక్షణ"</string> <string name="menu_sort" msgid="7677740407158414452">"ఇలా క్రమబద్ధీకరించు"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"అన్నీ ఎంచుకోండి"</string> <string name="menu_copy" msgid="3612326052677229148">"ఇక్కడికి కాపీ చేయి…"</string> <string name="menu_move" msgid="1828090633118079817">"దీనికి తరలించు..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"కొత్త విండో"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"కాపీ చేయి"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"అతికించు"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"అంతర్గత నిల్వను చూపు"</string> diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml index 8a49708ad591..47e12b635317 100644 --- a/packages/DocumentsUI/res/values-th/strings.xml +++ b/packages/DocumentsUI/res/values-th/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"ไฟล์"</string> <string name="title_open" msgid="4353228937663917801">"เปิดจาก"</string> <string name="title_save" msgid="2433679664882857999">"บันทึกไปยัง"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"สร้างโฟลเดอร์"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"มุมมองตาราง"</string> <string name="menu_list" msgid="7279285939892417279">"มุมมองรายการ"</string> <string name="menu_sort" msgid="7677740407158414452">"จัดเรียงตาม"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"เลือกทั้งหมด"</string> <string name="menu_copy" msgid="3612326052677229148">"คัดลอกไปยัง…"</string> <string name="menu_move" msgid="1828090633118079817">"ย้ายไปที่…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"หน้าต่างใหม่"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"คัดลอก"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"วาง"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"แสดงที่จัดเก็บภายใน"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"คัดลอก"</string> <string name="button_move" msgid="2202666023104202232">"ย้าย"</string> <string name="button_dismiss" msgid="3714065566893946085">"ปิด"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"ลองอีกครั้ง"</string> <string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string> <string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string> <string name="sort_size" msgid="3350681319735474741">"ตามขนาด"</string> diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml index 5c0dc12e0353..b09820c4be79 100644 --- a/packages/DocumentsUI/res/values-tl/strings.xml +++ b/packages/DocumentsUI/res/values-tl/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Mga File"</string> <string name="title_open" msgid="4353228937663917801">"Buksan mula sa"</string> <string name="title_save" msgid="2433679664882857999">"I-save sa"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Gumawa ng folder"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"View na grid"</string> <string name="menu_list" msgid="7279285939892417279">"View na listahan"</string> <string name="menu_sort" msgid="7677740407158414452">"Uriin ayon sa"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Piliin lahat"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopyahin sa..."</string> <string name="menu_move" msgid="1828090633118079817">"Ilipat sa…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Bagong window"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopyahin"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"I-paste"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ipakita internal storage"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopyahin"</string> <string name="button_move" msgid="2202666023104202232">"Ilipat"</string> <string name="button_dismiss" msgid="3714065566893946085">"I-dismiss"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Subukang Muli"</string> <string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string> <string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string> <string name="sort_size" msgid="3350681319735474741">"Ayon sa laki"</string> diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml index 092b38ee7eef..50fa357e4498 100644 --- a/packages/DocumentsUI/res/values-tr/strings.xml +++ b/packages/DocumentsUI/res/values-tr/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Dosyalar"</string> <string name="title_open" msgid="4353228937663917801">"Şuradan aç:"</string> <string name="title_save" msgid="2433679664882857999">"Şuraya kaydet:"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Klasör oluştur"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Tablo görünümü"</string> <string name="menu_list" msgid="7279285939892417279">"Liste görünümü"</string> <string name="menu_sort" msgid="7677740407158414452">"Sıralama ölçütü"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Tümünü seç"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopyala…"</string> <string name="menu_move" msgid="1828090633118079817">"Taşı..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Yeni pencere"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopyala"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Yapıştır"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Dahili depolamayı göster"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string> <string name="button_move" msgid="2202666023104202232">"Taşı"</string> <string name="button_dismiss" msgid="3714065566893946085">"Kapat"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Tekrar Dene"</string> <string name="sort_name" msgid="9183560467917256779">"Ada göre"</string> <string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string> <string name="sort_size" msgid="3350681319735474741">"Boyuta göre"</string> diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml index dff37c3eb316..7382bf83a7f0 100644 --- a/packages/DocumentsUI/res/values-uk/strings.xml +++ b/packages/DocumentsUI/res/values-uk/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Файли"</string> <string name="title_open" msgid="4353228937663917801">"Відкрити"</string> <string name="title_save" msgid="2433679664882857999">"Зберегти в"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Створити папку"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Режим таблиці"</string> <string name="menu_list" msgid="7279285939892417279">"Режим списку"</string> <string name="menu_sort" msgid="7677740407158414452">"Параметри сортування"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Вибрати все"</string> <string name="menu_copy" msgid="3612326052677229148">"Копіювати в…"</string> <string name="menu_move" msgid="1828090633118079817">"Перемістити в…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Нове вікно"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копіювати"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Вставити"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Показати внутр. пам’ять"</string> diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml index 82822ecdfe8d..0e5544f5588a 100644 --- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml +++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"فائلیں"</string> <string name="title_open" msgid="4353228937663917801">"کھولیں از"</string> <string name="title_save" msgid="2433679664882857999">"اس میں محفوظ کریں"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"فولڈر بنائیں"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"گرڈ منظر"</string> <string name="menu_list" msgid="7279285939892417279">"فہرست منظر"</string> <string name="menu_sort" msgid="7677740407158414452">"ترتیب دیں بلحاظ"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"سبھی کو منتخب کریں"</string> <string name="menu_copy" msgid="3612326052677229148">"اس میں کاپی کریں…"</string> <string name="menu_move" msgid="1828090633118079817">"اس میں منتقل کریں…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"نئی ونڈو"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"کاپی کریں"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"پیسٹ کریں"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"داخلی اسٹوریج دکھائیں"</string> diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml index d0cfacc8bc8c..9cc6bca0405a 100644 --- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml +++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Fayllar"</string> <string name="title_open" msgid="4353228937663917801">"Ochish"</string> <string name="title_save" msgid="2433679664882857999">"Saqlash"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Jild yaratish"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Katak ko‘rinishida"</string> <string name="menu_list" msgid="7279285939892417279">"Ro‘yxat ko‘rinishida"</string> <string name="menu_sort" msgid="7677740407158414452">"Saralash"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Barchasini belgilash"</string> <string name="menu_copy" msgid="3612326052677229148">"Nusxalash…"</string> <string name="menu_move" msgid="1828090633118079817">"Ko‘chirib o‘tkazish…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Yangi oyna"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Nusxalash"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Joylash"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ichki xotirani ko‘rsatish"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Nusxalash"</string> <string name="button_move" msgid="2202666023104202232">"Ko‘chirib o‘tkazish"</string> <string name="button_dismiss" msgid="3714065566893946085">"O‘chirish"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Qayta urinish"</string> <string name="sort_name" msgid="9183560467917256779">"Nomi bo‘yicha"</string> <string name="sort_date" msgid="586080032956151448">"Tahrir sanasi bo‘yicha"</string> <string name="sort_size" msgid="3350681319735474741">"Hajmi bo‘yicha"</string> diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml index 4583362fc6ab..1d553388dab0 100644 --- a/packages/DocumentsUI/res/values-vi/strings.xml +++ b/packages/DocumentsUI/res/values-vi/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Tệp"</string> <string name="title_open" msgid="4353228937663917801">"Mở từ"</string> <string name="title_save" msgid="2433679664882857999">"Lưu vào"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Tạo thư mục"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Chế độ xem lưới"</string> <string name="menu_list" msgid="7279285939892417279">"Chế độ xem danh sách"</string> <string name="menu_sort" msgid="7677740407158414452">"Sắp xếp theo"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Chọn tất cả"</string> <string name="menu_copy" msgid="3612326052677229148">"Sao chép vào…"</string> <string name="menu_move" msgid="1828090633118079817">"Chuyển tới..."</string> + <string name="menu_new_window" msgid="1226032889278727538">"Cửa sổ mới"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Sao chép"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Dán"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Hiển thị bộ nhớ trong"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"Sao chép"</string> <string name="button_move" msgid="2202666023104202232">"Di chuyển"</string> <string name="button_dismiss" msgid="3714065566893946085">"Loại bỏ"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"Thử lại"</string> <string name="sort_name" msgid="9183560467917256779">"Theo tên"</string> <string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string> <string name="sort_size" msgid="3350681319735474741">"Theo kích thước"</string> diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml index d577e14c8f40..7e2e3d501880 100644 --- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"文件"</string> <string name="title_open" msgid="4353228937663917801">"打开文件"</string> <string name="title_save" msgid="2433679664882857999">"保存文件"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"新建文件夹"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"网格视图"</string> <string name="menu_list" msgid="7279285939892417279">"列表视图"</string> <string name="menu_sort" msgid="7677740407158414452">"排序依据"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"全选"</string> <string name="menu_copy" msgid="3612326052677229148">"复制到…"</string> <string name="menu_move" msgid="1828090633118079817">"移动到…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"新建窗口"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"复制"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"粘贴"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"显示内部存储设备"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"复制"</string> <string name="button_move" msgid="2202666023104202232">"移动"</string> <string name="button_dismiss" msgid="3714065566893946085">"关闭"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"重试"</string> <string name="sort_name" msgid="9183560467917256779">"按名称"</string> <string name="sort_date" msgid="586080032956151448">"按修改日期"</string> <string name="sort_size" msgid="3350681319735474741">"按大小"</string> diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml index 3d44047126b9..6cbdf0149e25 100644 --- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"檔案"</string> <string name="title_open" msgid="4353228937663917801">"開啟檔案"</string> <string name="title_save" msgid="2433679664882857999">"儲存至"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"建立資料夾"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"格狀檢視"</string> <string name="menu_list" msgid="7279285939892417279">"清單檢視"</string> <string name="menu_sort" msgid="7677740407158414452">"排序方式"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"全部選取"</string> <string name="menu_copy" msgid="3612326052677229148">"複製到…"</string> <string name="menu_move" msgid="1828090633118079817">"移至…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"新視窗"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"複製"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"貼上"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"複製"</string> <string name="button_move" msgid="2202666023104202232">"移動"</string> <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"再試一次"</string> <string name="sort_name" msgid="9183560467917256779">"按名稱"</string> <string name="sort_date" msgid="586080032956151448">"按修改日期"</string> <string name="sort_size" msgid="3350681319735474741">"按大小"</string> diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml index aaad98c89851..850f9b0d8a5d 100644 --- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"檔案"</string> <string name="title_open" msgid="4353228937663917801">"開啟檔案"</string> <string name="title_save" msgid="2433679664882857999">"儲存至"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"建立資料夾"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"格狀檢視"</string> <string name="menu_list" msgid="7279285939892417279">"清單檢視"</string> <string name="menu_sort" msgid="7677740407158414452">"排序依據"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"全選"</string> <string name="menu_copy" msgid="3612326052677229148">"複製到…"</string> <string name="menu_move" msgid="1828090633118079817">"移至…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"新視窗"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"複製"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"貼上"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string> @@ -45,8 +47,7 @@ <string name="button_copy" msgid="8706475544635021302">"複製"</string> <string name="button_move" msgid="2202666023104202232">"移動"</string> <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string> - <!-- no translation found for button_retry (4392027584153752797) --> - <skip /> + <string name="button_retry" msgid="4392027584153752797">"再試一次"</string> <string name="sort_name" msgid="9183560467917256779">"依名稱"</string> <string name="sort_date" msgid="586080032956151448">"依修改日期"</string> <string name="sort_size" msgid="3350681319735474741">"依大小"</string> diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml index 8f20cc4db941..fdf278d34a84 100644 --- a/packages/DocumentsUI/res/values-zu/strings.xml +++ b/packages/DocumentsUI/res/values-zu/strings.xml @@ -20,7 +20,8 @@ <string name="files_label" msgid="6051402950202690279">"Amafayela"</string> <string name="title_open" msgid="4353228937663917801">"Vula kusuka ku-"</string> <string name="title_save" msgid="2433679664882857999">"Londoloza ku-"</string> - <string name="menu_create_dir" msgid="5947289605844398389">"Dala ifolda"</string> + <!-- no translation found for menu_create_dir (2547620241173881754) --> + <skip /> <string name="menu_grid" msgid="6878021334497835259">"Ukubuka kwegridi"</string> <string name="menu_list" msgid="7279285939892417279">"Ukubuka uhlu"</string> <string name="menu_sort" msgid="7677740407158414452">"Hlunga nge-"</string> @@ -33,6 +34,7 @@ <string name="menu_select_all" msgid="8323579667348729928">"Khetha konke"</string> <string name="menu_copy" msgid="3612326052677229148">"Kopishela ku…"</string> <string name="menu_move" msgid="1828090633118079817">"Hambisa ku…"</string> + <string name="menu_new_window" msgid="1226032889278727538">"Iwindi elisha"</string> <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopisha"</string> <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Namathisela"</string> <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Bonisa isitoreji sangaphakathi"</string> diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml index ce5b17432e8e..ed7820b01b48 100644 --- a/packages/DocumentsUI/res/values/config.xml +++ b/packages/DocumentsUI/res/values/config.xml @@ -15,5 +15,5 @@ --> <resources> - <bool name="productivity_device">false</bool> + <bool name="productivity_device">true</bool> </resources> diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index a4acb604c1ef..d21b5eec7d4f 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -27,7 +27,7 @@ <string name="title_save">Save to</string> <!-- Menu item that creates a new directory/folder at the current location [CHAR LIMIT=24] --> - <string name="menu_create_dir">Create folder</string> + <string name="menu_create_dir">New folder</string> <!-- Menu item that switches view to show documents as a large-format grid of thumbnails [CHAR LIMIT=24] --> <string name="menu_grid">Grid view</string> <!-- Menu item that switches view to show documents as a list [CHAR LIMIT=24] --> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index ab0f666ef5d3..caaa2b9be0a3 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -128,10 +128,10 @@ abstract class BaseActivity extends Activity { @Override public boolean onPrepareOptionsMenu(Menu menu) { - boolean shown = super.onPrepareOptionsMenu(menu); + super.onPrepareOptionsMenu(menu); final RootInfo root = getCurrentRoot(); - final DocumentInfo cwd = getCurrentDirectory(); + final boolean inRecents = getCurrentDirectory() == null; final MenuItem sort = menu.findItem(R.id.menu_sort); final MenuItem sortSize = menu.findItem(R.id.menu_sort_size); @@ -141,24 +141,28 @@ abstract class BaseActivity extends Activity { final MenuItem fileSize = menu.findItem(R.id.menu_file_size); final MenuItem settings = menu.findItem(R.id.menu_settings); - mSearchManager.update(root); + // I'm thinkin' this isn't necesary here. If it is...'cuz of a bug.... + // then uncomment the linke and let's get a proper bug reference here. + // mSearchManager.update(root); // Search uses backend ranking; no sorting - sort.setVisible(cwd != null && !mSearchManager.isSearching()); + sort.setVisible(!inRecents && !mSearchManager.isSearching()); + + // grid/list is effectively a toggle. + grid.setVisible(mState.derivedMode != State.MODE_GRID); + list.setVisible(mState.derivedMode != State.MODE_LIST); + + sortSize.setVisible(mState.showSize); // Only sort by size when visible + fileSize.setVisible(!mState.forceSize); + advanced.setVisible(!mState.forceAdvanced); + settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0); advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this) ? R.string.menu_advanced_hide : R.string.menu_advanced_show); fileSize.setTitle(LocalPreferences.getDisplayFileSize(this) ? R.string.menu_file_size_hide : R.string.menu_file_size_show); - sortSize.setVisible(mState.showSize); // Only sort by size when visible - fileSize.setVisible(!mState.showSize); - grid.setVisible(mState.derivedMode != State.MODE_GRID); - list.setVisible(mState.derivedMode != State.MODE_LIST); - advanced.setVisible(!mState.showAdvanced); - settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0); - - return shown; + return true; } State buildDefaultState() { @@ -277,6 +281,7 @@ abstract class BaseActivity extends Activity { return cwd != null && cwd.isCreateSupported() && !mSearchManager.isSearching() + && !root.isRecents() && !root.isDownloads(); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index 362052c58d53..66f8acd3fc50 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java @@ -119,7 +119,7 @@ public class CopyService extends IntentService { int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin : R.plurals.move_begin; - Shared.makeSnackbar(activity, + Snackbars.makeSnackbar(activity, res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()), Snackbar.LENGTH_SHORT).show(); activity.startService(copyIntent); diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java index 9f4451663706..c6425a6e41f2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java @@ -147,7 +147,7 @@ public class CreateDirectoryFragment extends DialogFragment { // Navigate into newly created child mActivity.onDirectoryCreated(result); } else { - Shared.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show(); + Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show(); } mActivity.setPending(false); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index b3ce103b4c63..0abbf4e4996f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -44,7 +44,6 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.Loader; -import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -54,7 +53,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.CancellationSignal; -import android.os.Handler; import android.os.Looper; import android.os.OperationCanceledException; import android.os.Parcelable; @@ -134,8 +132,6 @@ public class DirectoryFragment extends Fragment { private Model mModel; private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener(); - private final Handler mHandler = new Handler(Looper.getMainLooper()); - private View mEmptyView; private RecyclerView mRecView; @@ -217,8 +213,6 @@ public class DirectoryFragment extends Fragment { @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final Context context = inflater.getContext(); - final Resources res = context.getResources(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); mMessageBar = MessageBar.create(getChildFragmentManager()); @@ -678,6 +672,7 @@ public class DirectoryFragment extends Fragment { checkNotNull(mMenu); // Delegate update logic to our owning action, since specialized logic is desired. mFragmentTuner.updateActionMenu(mMenu, mType, mNoDeleteCount == 0); + Menus.disableHiddenItems(mMenu); } @Override @@ -799,13 +794,12 @@ public class DirectoryFragment extends Fragment { private void deleteDocuments(final Selection selected) { Context context = getActivity(); - ContentResolver resolver = context.getContentResolver(); String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size()); mModel.markForDeletion(selected); final Activity activity = getActivity(); - Shared.makeSnackbar(activity, message, Snackbar.LENGTH_LONG) + Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG) .setAction( R.string.undo, new android.view.View.OnClickListener() { @@ -823,7 +817,7 @@ public class DirectoryFragment extends Fragment { new Model.DeletionListener() { @Override public void onError() { - Shared.makeSnackbar( + Snackbars.makeSnackbar( activity, R.string.toast_failed_delete, Snackbar.LENGTH_LONG) @@ -1244,7 +1238,7 @@ public class DirectoryFragment extends Fragment { private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) { if (!canCopy(docs, destination)) { - Shared.makeSnackbar( + Snackbars.makeSnackbar( getActivity(), R.string.clipboard_files_cannot_paste, Snackbar.LENGTH_SHORT) @@ -1298,7 +1292,7 @@ public class DirectoryFragment extends Fragment { void onDocumentsReady(List<DocumentInfo> docs) { mClipper.clipDocuments(docs); Activity activity = getActivity(); - Shared.makeSnackbar(activity, + Snackbars.makeSnackbar(activity, activity.getResources().getQuantityString( R.plurals.clipboard_files_clipped, docs.size(), docs.size()), Snackbar.LENGTH_SHORT).show(); @@ -1608,23 +1602,25 @@ public class DirectoryFragment extends Fragment { @Override public void updateActionMenu(Menu menu, int dirType, boolean canDelete) { + boolean copyEnabled = mManaging && dirType != TYPE_RECENT_OPEN; + // TODO: The selection needs to be deletable. + boolean moveEnabled = + SystemProperties.getBoolean("debug.documentsui.enable_move", false); + menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled); final MenuItem open = menu.findItem(R.id.menu_open); final MenuItem share = menu.findItem(R.id.menu_share); final MenuItem delete = menu.findItem(R.id.menu_delete); final MenuItem copyTo = menu.findItem(R.id.menu_copy_to); final MenuItem moveTo = menu.findItem(R.id.menu_move_to); - final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard); open.setVisible(!mManaging); share.setVisible(mManaging); delete.setVisible(mManaging && canDelete); - // Disable copying from the Recents view. - copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN); - moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false)); - - // Only shown in files mode. - copyToClipboard.setVisible(false); + copyTo.setVisible(copyEnabled); + copyTo.setEnabled(copyEnabled); + moveTo.setVisible(moveEnabled); + moveTo.setEnabled(moveEnabled); } @Override @@ -1638,13 +1634,14 @@ public class DirectoryFragment extends Fragment { @Override public void updateActionMenu(Menu menu, int dirType, boolean canDelete) { + menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(dirType != TYPE_RECENT_OPEN); + menu.findItem(R.id.menu_share).setVisible(true); menu.findItem(R.id.menu_delete).setVisible(canDelete); - menu.findItem(R.id.menu_copy_to_clipboard).setVisible(true); menu.findItem(R.id.menu_open).setVisible(false); - menu.findItem(R.id.menu_copy_to).setVisible(false); - menu.findItem(R.id.menu_move_to).setVisible(false); + menu.findItem(R.id.menu_copy_to).setVisible(true); + menu.findItem(R.id.menu_move_to).setVisible(true); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index ced03cc83451..6b428f58441c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -89,8 +89,6 @@ public class DocumentsActivity extends BaseActivity { setTheme(R.style.DocumentsNonDialogTheme); } - final Context context = this; - if (mShowAsDialog) { mDrawer = DrawerController.createDummy(); @@ -314,42 +312,36 @@ public class DocumentsActivity extends BaseActivity { public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); final MenuItem grid = menu.findItem(R.id.menu_grid); final MenuItem list = menu.findItem(R.id.menu_list); - final MenuItem advanced = menu.findItem(R.id.menu_advanced); final MenuItem fileSize = menu.findItem(R.id.menu_file_size); final MenuItem settings = menu.findItem(R.id.menu_settings); - boolean fileSizeVisible = mState.showSize && !mState.forceSize; - if (mState.action == ACTION_CREATE + boolean recents = cwd == null; + boolean picking = mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE - || mState.action == ACTION_OPEN_COPY_DESTINATION) { - createDir.setVisible(cwd != null && cwd.isCreateSupported()); - mSearchManager.showMenu(false); - - // No display options in recent directories - if (cwd == null) { - grid.setVisible(false); - list.setVisible(false); - fileSizeVisible = false; - } + || mState.action == ACTION_OPEN_COPY_DESTINATION; - if (mState.action == ACTION_CREATE) { - final FragmentManager fm = getFragmentManager(); - SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported()); - } - } else { - createDir.setVisible(false); - } + createDir.setVisible(picking && !recents && cwd.isCreateSupported()); + mSearchManager.showMenu(!picking); - advanced.setVisible(!mState.forceAdvanced); - fileSize.setVisible(fileSizeVisible); + // No display options in recent directories + grid.setVisible(!(picking && recents)); + list.setVisible(!(picking && recents)); + + fileSize.setVisible(fileSize.isVisible() && !picking); settings.setVisible(false); + if (mState.action == ACTION_CREATE) { + final FragmentManager fm = getFragmentManager(); + SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported()); + } + + Menus.disableHiddenItems(menu); + return true; } @@ -611,7 +603,7 @@ public class DocumentsActivity extends BaseActivity { if (result != null) { onTaskFinished(result); } else { - Shared.makeSnackbar( + Snackbars.makeSnackbar( DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show(); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index f6a5131c8244..70ddf5916f2c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -225,30 +225,23 @@ public class FilesActivity extends BaseActivity { @Override public boolean onPrepareOptionsMenu(Menu menu) { - boolean shown = super.onPrepareOptionsMenu(menu); - - menu.findItem(R.id.menu_file_size).setVisible(true); - menu.findItem(R.id.menu_advanced).setVisible(true); + super.onPrepareOptionsMenu(menu); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); final MenuItem newWindow = menu.findItem(R.id.menu_new_window); final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); - boolean canCreateDir = canCreateDirectory(); - createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - createDir.setVisible(canCreateDir); - createDir.setEnabled(canCreateDir); + createDir.setVisible(true); + createDir.setEnabled(canCreateDirectory()); + + pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); newWindow.setVisible(mProductivityDevice); - newWindow.setEnabled(mProductivityDevice); - - pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - pasteFromCb.setVisible(true); - pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); - return shown; + Menus.disableHiddenItems(menu, pasteFromCb); + return true; } @Override @@ -347,7 +340,7 @@ public class FilesActivity extends BaseActivity { try { startActivity(intent); } catch (ActivityNotFoundException ex2) { - Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show(); + Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show(); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java index ed7333d31149..14a33f9c1cc1 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java @@ -140,6 +140,7 @@ public class ManageRootActivity extends BaseActivity { @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); + Menus.disableHiddenItems(menu); return true; } @@ -184,7 +185,7 @@ public class ManageRootActivity extends BaseActivity { try { startActivity(view); } catch (ActivityNotFoundException ex2) { - Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT) + Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT) .show(); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/Menus.java b/packages/DocumentsUI/src/com/android/documentsui/Menus.java new file mode 100644 index 000000000000..3f43a3d30c8d --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/Menus.java @@ -0,0 +1,50 @@ +/* + * 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.documentsui; + +import android.view.Menu; +import android.view.MenuItem; + +final class Menus { + + private Menus() {} + + /** + * Disables hidden menu items so that they are not invokable via command shortcuts + */ + static void disableHiddenItems(Menu menu, MenuItem... exclusions) { + for (int i = 0; i < menu.size(); i++) { + MenuItem item = menu.getItem(i); + if (item.isVisible()) { + continue; + } + if (contains(exclusions, item)) { + continue; + } + item.setEnabled(false); + } + } + + private static boolean contains(MenuItem[] exclusions, MenuItem item) { + for (int x = 0; x < exclusions.length; x++) { + if (exclusions[x] == item) { + return true; + } + } + return false; + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java index e06d6a52e004..a4d6dc57cd34 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java +++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java @@ -16,12 +16,7 @@ package com.android.documentsui; -import static com.android.internal.util.Preconditions.checkNotNull; - -import android.app.Activity; import android.content.Context; -import android.support.design.widget.Snackbar; -import android.view.View; /** @hide */ public final class Shared { @@ -35,14 +30,4 @@ public final class Shared { public static final String getQuantityString(Context context, int resourceId, int quantity) { return context.getResources().getQuantityString(resourceId, quantity, quantity); } - - public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) { - return makeSnackbar(activity, activity.getResources().getText(messageId), duration); - } - - public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration) - { - final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout)); - return Snackbar.make(view, message, duration); - } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java new file mode 100644 index 000000000000..f48b298a4f2f --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java @@ -0,0 +1,37 @@ +/* + * 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.documentsui; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.app.Activity; +import android.support.design.widget.Snackbar; +import android.view.View; + +final class Snackbars { + private Snackbars() {} + + public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) { + return Snackbars.makeSnackbar(activity, activity.getResources().getText(messageId), duration); + } + + public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration) + { + final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout)); + return Snackbar.make(view, message, duration); + } +} diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 47e24e8e82f3..368f9f79a20b 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -13,3 +13,11 @@ -keep class com.android.systemui.statusbar.phone.PhoneStatusBar -keep class com.android.systemui.statusbar.tv.TvStatusBar -keep class com.android.systemui.recents.* + +-keepclassmembers class ** { + public void onBusEvent(**); + public void onInterprocessBusEvent(**); +} +-keepclassmembers class ** extends **.EventBus$InterprocessEvent { + public <init>(android.os.Bundle); +}
\ No newline at end of file diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index f8fc232106bb..b69fc0f4a8d8 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -325,8 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string> - <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string> - <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Անջատել օգտվողին"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Փոխել օգտվողին. ներկայիս օգտվողն է՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ընթացիկ օգտվողը՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index d91335c28279..732312684fba 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -393,7 +393,7 @@ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utöka"</string> <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Komprimera"</string> <string name="screen_pinning_title" msgid="3273740381976175811">"Skärmen har fästs"</string> - <string name="screen_pinning_description" msgid="1346522416878235405">"Detta visar skärmen tills du lossar den. Tryck länge på bakåtknappen och Översikt samtidigt om du vill lossa skärmen."</string> + <string name="screen_pinning_description" msgid="1346522416878235405">"Med den här funktionen är skärmen synlig tills du lossar den. Tryck länge på Tillbaka och Översikt samtidigt om du vill lossa skärmen."</string> <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Detta visar skärmen tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string> <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string> <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tack"</string> diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 23cc8f067d83..a78351a1ffbc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -74,6 +74,8 @@ import java.util.ArrayList; public class Recents extends SystemUI implements ActivityOptions.OnAnimationStartedListener, RecentsComponent { + public final static int EVENT_BUS_PRIORITY = 1; + final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab"; final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey"; final public static String EXTRA_RECENTS_VISIBILITY = "recentsVisibility"; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 9ce6b2c764b4..5c61c5ca66a2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -19,23 +19,32 @@ package com.android.systemui.recents; import android.app.Activity; import android.app.ActivityOptions; import android.app.SearchManager; +import android.app.TaskStackBuilder; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; import android.os.UserHandle; +import android.provider.Settings; import android.view.KeyEvent; import android.view.View; import android.view.ViewStub; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent; +import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.ResizeTaskEvent; +import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; import com.android.systemui.recents.misc.Console; import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.model.RecentsPackageMonitor; import com.android.systemui.recents.model.RecentsTaskLoadPlan; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; @@ -44,16 +53,17 @@ import com.android.systemui.recents.views.RecentsView; import com.android.systemui.recents.views.SystemBarScrimViews; import com.android.systemui.recents.views.ViewAnimation; -import java.lang.ref.WeakReference; import java.util.ArrayList; /** * The main Recents activity that is started from AlternateRecentsComponent. */ -public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks, - RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks { +public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks { + + public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1; RecentsConfiguration mConfig; + RecentsPackageMonitor mPackageMonitor; long mLastTabKeyEventTime; // Top level views @@ -318,12 +328,17 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // Register this activity with the event bus + EventBus.getDefault().register(this, EVENT_BUS_PRIORITY); + // For the non-primary user, ensure that the SystemServicesProxy and configuration is // initialized RecentsTaskLoader.initialize(this); SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); mConfig = RecentsConfiguration.initialize(this, ssp); mConfig.update(this, ssp, ssp.getWindowRect()); + mPackageMonitor = new RecentsPackageMonitor(); // Initialize the widget host (the host id is static and does not change) mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId); @@ -371,7 +386,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView registerReceiver(mServiceBroadcastReceiver, filter); // Register any broadcast receivers for the task loader - loader.registerReceivers(this, mRecentsView); + mPackageMonitor.register(this); // Update the recent tasks updateRecentsTasks(); @@ -415,7 +430,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView unregisterReceiver(mServiceBroadcastReceiver); // Unregister any broadcast receivers for the task loader - loader.unregisterReceivers(); + mPackageMonitor.unregister(); // Workaround for b/22542869, if the RecentsActivity is started again, but without going // through SystemUI, we need to reset the config launch flags to ensure that we do not @@ -437,6 +452,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Stop listening for widget package changes if there was one bound mAppWidgetHost.stopListening(); + EventBus.getDefault().unregister(this); } public void onEnterAnimationTriggered() { @@ -446,16 +462,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mRecentsView.startEnterRecentsAnimation(ctx); if (mSearchWidgetInfo != null) { - final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> cbRef = - new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>( - RecentsActivity.this); ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { @Override public void run() { // Start listening for widget package changes if there is one bound - RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = cbRef.get(); - if (cb != null) { - mAppWidgetHost.startListening(cb); + if (mAppWidgetHost != null) { + mAppWidgetHost.startListening(); } } }); @@ -530,11 +542,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView return mResizeTaskDebugDialog; } - @Override - public void onTaskResize(Task t) { - getResizeTaskDebugDialog().showResizeTaskDialog(t, mRecentsView); - } - /**** RecentsView.RecentsViewCallbacks Implementation ****/ @Override @@ -572,10 +579,40 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mAfterPauseRunnable = r; } - /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/ + /**** EventBus events ****/ - @Override - public void refreshSearchWidgetView() { + public final void onBusEvent(AppWidgetProviderChangedEvent event) { + refreshSearchWidgetView(); + } + + public final void onBusEvent(ShowApplicationInfoEvent event) { + // Create a new task stack with the application info details activity + Intent baseIntent = event.task.key.baseIntent; + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null)); + intent.setComponent(intent.resolveActivity(getPackageManager())); + TaskStackBuilder.create(this) + .addNextIntentWithParentStack(intent).startActivities(null, + new UserHandle(event.task.key.userId)); + + // Keep track of app-info invocations + MetricsLogger.count(this, "overview_app_info", 1); + } + + public final void onBusEvent(DismissTaskEvent event) { + // Remove any stored data from the loader + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); + loader.deleteTaskData(event.task, false); + + // Remove the task from activity manager + loader.getSystemServicesProxy().removeTask(event.task.key.id); + } + + public final void onBusEvent(ResizeTaskEvent event) { + getResizeTaskDebugDialog().showResizeTaskDialog(event.task, mRecentsView); + } + + private void refreshSearchWidgetView() { if (mSearchWidgetInfo != null) { SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); int searchWidgetId = ssp.getSearchAppWidgetId(this); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java index 0102332b17cb..fc96c11e4124 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java @@ -20,24 +20,19 @@ import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent; /** Our special app widget host for the Search widget */ public class RecentsAppWidgetHost extends AppWidgetHost { - /* Callbacks to notify when an app package changes */ - interface RecentsAppWidgetHostCallbacks { - void refreshSearchWidgetView(); - } - - RecentsAppWidgetHostCallbacks mCb; boolean mIsListening; public RecentsAppWidgetHost(Context context, int hostId) { super(context, hostId); } - public void startListening(RecentsAppWidgetHostCallbacks cb) { - mCb = cb; + public void startListening() { if (!mIsListening) { mIsListening = true; super.startListening(); @@ -47,11 +42,9 @@ public class RecentsAppWidgetHost extends AppWidgetHost { @Override public void stopListening() { if (mIsListening) { + mIsListening = false; super.stopListening(); } - // Ensure that we release any references to the callbacks - mCb = null; - mIsListening = false; } @Override @@ -66,8 +59,8 @@ public class RecentsAppWidgetHost extends AppWidgetHost { @Override protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) { super.onProviderChanged(appWidgetId, appWidgetInfo); - if (mIsListening && mCb != null) { - mCb.refreshSearchWidgetView(); + if (mIsListening) { + EventBus.getDefault().send(new AppWidgetProviderChangedEvent()); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java new file mode 100644 index 000000000000..ef543d0715f7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2014 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; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.Log; +import android.util.MutableBoolean; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +/** + * Represents a subscriber, which implements various event bus handler methods. + */ +class Subscriber { + private WeakReference<Object> mSubscriber; + + long registrationTime; + + Subscriber(Object subscriber, long registrationTime) { + mSubscriber = new WeakReference<>(subscriber); + this.registrationTime = registrationTime; + } + + public String toString(int priority) { + Object sub = mSubscriber.get(); + String id = Integer.toHexString(System.identityHashCode(sub)); + return sub.getClass().getSimpleName() + " [0x" + id + ", P" + priority + "]"; + } + + public Object getReference() { + return mSubscriber.get(); + } +} + +/** + * Represents an event handler with a priority. + */ +class EventHandler { + int priority; + Subscriber subscriber; + EventHandlerMethod method; + + EventHandler(Subscriber subscriber, EventHandlerMethod method, int priority) { + this.subscriber = subscriber; + this.method = method; + this.priority = priority; + } + + @Override + public String toString() { + return subscriber.toString(priority) + " " + method.toString(); + } +} + +/** + * Represents the low level method handling a particular event. + */ +class EventHandlerMethod { + private Method mMethod; + Class<? extends EventBus.Event> eventType; + + EventHandlerMethod(Method method, Class<? extends EventBus.Event> eventType) { + mMethod = method; + mMethod.setAccessible(true); + this.eventType = eventType; + } + + public void invoke(Object target, EventBus.Event event) + throws InvocationTargetException, IllegalAccessException { + mMethod.invoke(target, event); + } + + @Override + public String toString() { + return mMethod.getName() + "(" + eventType.getSimpleName() + ")"; + } +} + +/** + * A simple in-process event bus. It is simple because we can make assumptions about the state of + * SystemUI and Recent's lifecycle. + * + * <p> + * Currently, there is a single EventBus that handles {@link EventBus.Event}s for each subscriber + * on the main application thread. Publishers can send() events to synchronously call subscribers + * of that event, or post() events to be processed in the next run of the {@link Looper}. In + * addition, the EventBus supports sending and handling {@link EventBus.InterprocessEvent}s + * (within the same package) implemented using standard {@link BroadcastReceiver} mechanism. + * Interprocess events must be posted using postInterprocess() to ensure that it is dispatched + * correctly across processes. + * + * <p> + * Subscribers must be registered with a particular EventBus before they will receive events, and + * handler methods must match a specific signature. + * + * <p> + * Event method signature:<ul> + * <li>Methods must be public final + * <li>Methods must return void + * <li>Methods must be called "onBusEvent" + * <li>Methods must take one parameter, of class type deriving from {@link EventBus.Event} + * </ul> + * + * <p> + * Interprocess-Event method signature:<ul> + * <li>Methods must be public final + * <li>Methods must return void + * <li>Methods must be called "onInterprocessBusEvent" + * <li>Methods must take one parameter, of class type deriving from {@link EventBus.InterprocessEvent} + * </ul> + * </p> + * + * </p> + * Each subscriber can be registered with a given priority (default 1), and events will be dispatch + * in decreasing order of priority. For subscribers with the same priority, events will be + * dispatched by latest registration time to earliest. + * + * <p> + * Interprocess events must extend {@link EventBus.InterprocessEvent}, have a constructor which + * takes a {@link Bundle} and implement toBundle(). This allows us to serialize events to be sent + * across processes. + * + * <p> + * Caveats:<ul> + * <li>The EventBus keeps a {@link WeakReference} to the publisher to prevent memory leaks, so + * there must be another strong reference to the publisher for it to not get garbage-collected and + * continue receiving events. + * <li>Because the event handlers are called back using reflection, the EventBus is not intended + * for use in tight, performance criticial loops. For most user input/system callback events, this + * is generally of low enough frequency to use the EventBus. + * <li>Because the event handlers are called back using reflection, there will often be no + * references to them from actual code. The proguard configuration will be need to be updated to + * keep these extra methods: + * + * -keepclassmembers class ** { + * public void onBusEvent(**); + * public void onInterprocessBusEvent(**); + * } + * -keepclassmembers class ** extends **.EventBus$InterprocessEvent { + * public <init>(android.os.Bundle); + * } + * + * <li>Subscriber registration can be expensive depending on the subscriber's {@link Class}. This + * is only done once per class type, but if possible, it is best to pre-register an instance of + * that class beforehand or when idle. + * <li>Each event should be sent once. Events may hold internal information about the current + * dispatch, or may be queued to be dispatched on another thread (if posted from a non-main thread), + * so it may be unsafe to edit, change, or re-send the event again. + * <li>Events should follow a pattern of public-final POD (plain old data) objects, where they are + * initialized by the constructor and read by each subscriber of that event. Subscribers should + * never alter events as they are processed, and this enforces that pattern. + * </ul> + * + * <p> + * Future optimizations: + * <li>throw exception/log when a subscriber loses the reference + * <li>trace cost per registration & invocation + * <li>trace cross-process invocation + * <li>register(subscriber, Class<?>...) -- pass in exact class types you want registered + * <li>setSubscriberEventHandlerPriority(subscriber, Class<Event>, priority) + * <li>allow subscribers to implement interface, ie. EventBus.Subscriber, which lets then test a + * message before invocation (ie. check if task id == this task id) + * <li>add postOnce() which automatically debounces + * <li>add postDelayed() which delays / postDelayedOnce() which delays and bounces + * <li>consolidate register() and registerInterprocess() + * <li>sendForResult<ReturnType>(Event) to send and get a result, but who will send the + * result? + * </p> + */ +public class EventBus extends BroadcastReceiver { + + public static final String TAG = "EventBus"; + + /** + * An event super class that allows us to track internal event state across subscriber + * invocations. + * + * Events should not be edited by subscribers. + */ + public static class Event { + // Indicates that this event's dispatch should be traced and logged to logcat + boolean trace; + // Indicates that this event must be posted on the EventBus's looper thread before invocation + boolean requiresPost; + // Not currently exposed, allows a subscriber to cancel further dispatch of this event + boolean cancelled; + + // Only accessible from derived events + protected Event() {} + } + + /** + * An inter-process event super class that allows us to track user state across subscriber + * invocations. + */ + public static class InterprocessEvent extends Event { + private static final String EXTRA_USER = "_user"; + + // The user which this event originated from + public final int user; + + // Only accessible from derived events + protected InterprocessEvent(int user) { + this.user = user; + } + + /** + * Called from the event bus + */ + protected InterprocessEvent(Bundle b) { + user = b.getInt(EXTRA_USER); + } + + protected Bundle toBundle() { + Bundle b = new Bundle(); + b.putInt(EXTRA_USER, user); + return b; + } + } + + /** + * Proguard must also know, and keep, all methods matching this signature. + * + * -keepclassmembers class ** { + * public void onBusEvent(**); + * public void onInterprocessBusEvent(**); + * } + */ + private static final String METHOD_PREFIX = "onBusEvent"; + private static final String INTERPROCESS_METHOD_PREFIX = "onInterprocessBusEvent"; + + // Ensures that interprocess events can only be sent from a process holding this permission. */ + private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; + + // Used for passing event data across process boundaries + private static final String EXTRA_INTERPROCESS_EVENT_BUNDLE = "interprocess_event_bundle"; + + // The default priority of all subscribers + private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1; + + // Used for debugging everything + private static final boolean DEBUG_TRACE_ALL = false; + + // Orders the handlers by priority and registration time + private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() { + @Override + public int compare(EventHandler h1, EventHandler h2) { + // Rank the handlers by priority descending, followed by registration time descending. + // aka. the later registered + if (h1.priority != h2.priority) { + return h2.priority - h1.priority; + } else { + return Long.compare(h2.subscriber.registrationTime, h1.subscriber.registrationTime); + } + } + }; + + // Used for initializing the default bus + private static final Object sLock = new Object(); + private static EventBus sDefaultBus; + + // The handler to post all events + private Handler mHandler; + + // Keep track of whether we have registered a broadcast receiver already, so that we can + // unregister ourselves before re-registering again with a new IntentFilter. + private boolean mHasRegisteredReceiver; + + /** + * Map from event class -> event handler list. Keeps track of the actual mapping from event + * to subscriber method. + */ + private HashMap<Class<? extends Event>, ArrayList<EventHandler>> mEventTypeMap = new HashMap<>(); + + /** + * Map from subscriber class -> event handler method lists. Used to determine upon registration + * of a new subscriber whether we need to read all the subscriber's methods again using + * reflection or whether we can just add the subscriber to the event type map. + */ + private HashMap<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>(); + + /** + * Map from interprocess event name -> interprocess event class. Used for mapping the event + * name after receiving the broadcast, to the event type. After which a new instance is created + * and posted in the local process. + */ + private HashMap<String, Class<? extends InterprocessEvent>> mInterprocessEventNameMap = new HashMap<>(); + + /** + * Set of all currently registered subscribers + */ + private ArrayList<Subscriber> mSubscribers = new ArrayList<>(); + + // For tracing + private int mCallCount; + private long mCallDurationMicros; + + /** + * Private constructor to create an event bus for a given looper. + */ + private EventBus(Looper looper) { + mHandler = new Handler(looper); + } + + /** + * @return the default event bus for the application's main thread. + */ + public static EventBus getDefault() { + if (sDefaultBus == null) + synchronized (sLock) { + if (sDefaultBus == null) { + if (DEBUG_TRACE_ALL) { + logWithPid("New EventBus"); + } + sDefaultBus = new EventBus(Looper.getMainLooper()); + } + } + return sDefaultBus; + } + + /** + * Registers a subscriber to receive events with the default priority. + * + * @param subscriber the subscriber to handle events. If this is the first instance of the + * subscriber's class type that has been registered, the class's methods will + * be scanned for appropriate event handler methods. + */ + public void register(Object subscriber) { + registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY, null); + } + + /** + * Registers a subscriber to receive events with the given priority. + * + * @param subscriber the subscriber to handle events. If this is the first instance of the + * subscriber's class type that has been registered, the class's methods will + * be scanned for appropriate event handler methods. + * @param priority the priority that this subscriber will receive events relative to other + * subscribers + */ + public void register(Object subscriber, int priority) { + registerSubscriber(subscriber, priority, null); + } + + /** + * Explicitly registers a subscriber to receive interprocess events with the default priority. + * + * @param subscriber the subscriber to handle events. If this is the first instance of the + * subscriber's class type that has been registered, the class's methods will + * be scanned for appropriate event handler methods. + */ + public void registerInterprocessAsCurrentUser(Context context, Object subscriber) { + registerInterprocessAsCurrentUser(context, subscriber, DEFAULT_SUBSCRIBER_PRIORITY); + } + + /** + * Registers a subscriber to receive interprocess events with the given priority. + * + * @param subscriber the subscriber to handle events. If this is the first instance of the + * subscriber's class type that has been registered, the class's methods will + * be scanned for appropriate event handler methods. + * @param priority the priority that this subscriber will receive events relative to other + * subscribers + */ + public void registerInterprocessAsCurrentUser(Context context, Object subscriber, int priority) { + if (DEBUG_TRACE_ALL) { + logWithPid("registerInterprocessAsCurrentUser(" + subscriber.getClass().getSimpleName() + ")"); + } + + // Register the subscriber normally, and update the broadcast receiver filter if this is + // a new subscriber type with interprocess events + MutableBoolean hasInterprocessEventsChanged = new MutableBoolean(false); + registerSubscriber(subscriber, priority, hasInterprocessEventsChanged); + if (DEBUG_TRACE_ALL) { + logWithPid("hasInterprocessEventsChanged: " + hasInterprocessEventsChanged.value); + } + if (hasInterprocessEventsChanged.value) { + registerReceiverForInterprocessEvents(context); + } + } + + /** + * Remove all EventHandlers pointing to the specified subscriber. This does not remove the + * mapping of subscriber type to event handler method, in case new instances of this subscriber + * are registered. + */ + public void unregister(Object subscriber) { + if (DEBUG_TRACE_ALL) { + logWithPid("unregister()"); + } + + // Fail immediately if we are being called from the non-main thread + long callingThreadId = Thread.currentThread().getId(); + if (callingThreadId != mHandler.getLooper().getThread().getId()) { + throw new RuntimeException("Can not unregister() a subscriber from a non-main thread."); + } + + // Return early if this is not a registered subscriber + if (!findRegisteredSubscriber(subscriber, true /* removeFoundSubscriber */)) { + return; + } + + Class<?> subscriberType = subscriber.getClass(); + ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType); + if (subscriberMethods != null) { + // For each of the event handlers the subscriber handles, remove all references of that + // handler + for (EventHandlerMethod method : subscriberMethods) { + ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(method.eventType); + for (int i = eventHandlers.size() - 1; i >= 0; i--) { + if (eventHandlers.get(i).subscriber.getReference() == subscriber) { + eventHandlers.remove(i); + } + } + } + } + } + + /** + * Explicit unregistration for interprocess event subscribers. This actually behaves exactly + * the same as unregister() since we also do not want to stop listening for specific + * inter-process messages in case new instances of that subscriber is registered. + */ + public void unregisterInterprocess(Context context, Object subscriber) { + if (DEBUG_TRACE_ALL) { + logWithPid("unregisterInterprocess()"); + } + unregister(subscriber); + } + + /** + * Sends an event to the subscribers of the given event type immediately. This can only be + * called from the same thread as the EventBus's looper thread (for the default EventBus, this + * is the main application thread). + */ + public void send(Event event) { + // Fail immediately if we are being called from the non-main thread + long callingThreadId = Thread.currentThread().getId(); + if (callingThreadId != mHandler.getLooper().getThread().getId()) { + throw new RuntimeException("Can not send() a message from a non-main thread."); + } + + if (DEBUG_TRACE_ALL) { + logWithPid("send(" + event.getClass().getSimpleName() + ")"); + } + + // Reset the event's cancelled state + event.requiresPost = false; + event.cancelled = false; + queueEvent(event); + } + + /** + * Post a message to the subscribers of the given event type. The messages will be posted on + * the EventBus's looper thread (for the default EventBus, this is the main application thread). + */ + public void post(Event event) { + if (DEBUG_TRACE_ALL) { + logWithPid("post(" + event.getClass().getSimpleName() + ")"); + } + + // Reset the event's cancelled state + event.requiresPost = true; + event.cancelled = false; + queueEvent(event); + } + + /** Prevent post()ing an InterprocessEvent */ + @Deprecated + public void post(InterprocessEvent event) { + throw new RuntimeException("Not supported, use postInterprocess"); + } + + /** Prevent send()ing an InterprocessEvent */ + @Deprecated + public void send(InterprocessEvent event) { + throw new RuntimeException("Not supported, use postInterprocess"); + } + + /** + * Posts an interprocess event. + */ + public void postInterprocess(Context context, final InterprocessEvent event) { + if (DEBUG_TRACE_ALL) { + logWithPid("postInterprocess(" + event.getClass().getSimpleName() + ")"); + } + String eventType = event.getClass().getName(); + Bundle eventBundle = event.toBundle(); + Intent intent = new Intent(eventType); + intent.setPackage(context.getPackageName()); + intent.putExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE, eventBundle); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | + Intent.FLAG_RECEIVER_FOREGROUND); + context.sendBroadcastAsUser(intent, UserHandle.ALL); + } + + /** + * Receiver for interprocess events. + */ + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG_TRACE_ALL) { + logWithPid("onReceive(" + intent.getAction() + ", user " + UserHandle.myUserId() + ")"); + } + + Bundle eventBundle = intent.getBundleExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE); + Class<? extends InterprocessEvent> eventType = mInterprocessEventNameMap.get(intent.getAction()); + try { + Constructor<? extends InterprocessEvent> ctor = eventType.getConstructor(Bundle.class); + send((Event) ctor.newInstance(eventBundle)); + } catch (NoSuchMethodException| + InvocationTargetException| + InstantiationException| + IllegalAccessException e) { + Log.e(TAG, "Failed to create InterprocessEvent", e); + } + } + + /** + * @return a dump of the current state of the EventBus + */ + public String dump() { + StringBuilder output = new StringBuilder(); + output.append("Registered class types:"); + output.append("\n"); + for (Class<?> clz : mSubscriberTypeMap.keySet()) { + output.append("\t"); + output.append(clz.getSimpleName()); + output.append("\n"); + } + output.append("Event map:"); + output.append("\n"); + for (Class<?> clz : mEventTypeMap.keySet()) { + output.append("\t"); + output.append(clz.getSimpleName()); + output.append(" -> "); + output.append("\n"); + ArrayList<EventHandler> handlers = mEventTypeMap.get(clz); + for (EventHandler handler : handlers) { + Object subscriber = handler.subscriber.getReference(); + if (subscriber != null) { + String id = Integer.toHexString(System.identityHashCode(subscriber)); + output.append("\t\t"); + output.append(subscriber.getClass().getSimpleName()); + output.append(" [0x" + id + ", #" + handler.priority + "]"); + output.append("\n"); + } + } + } + return output.toString(); + } + + /** + * Registers a new subscriber. + * + * @return return whether or not this + */ + private void registerSubscriber(Object subscriber, int priority, + MutableBoolean hasInterprocessEventsChangedOut) { + // Fail immediately if we are being called from the non-main thread + long callingThreadId = Thread.currentThread().getId(); + if (callingThreadId != mHandler.getLooper().getThread().getId()) { + throw new RuntimeException("Can not register() a subscriber from a non-main thread."); + } + + // Return immediately if this exact subscriber is already registered + if (findRegisteredSubscriber(subscriber, false /* removeFoundSubscriber */)) { + return; + } + + long t1 = 0; + if (DEBUG_TRACE_ALL) { + t1 = SystemClock.currentTimeMicro(); + logWithPid("registerSubscriber(" + subscriber.getClass().getSimpleName() + ")"); + } + Subscriber sub = new Subscriber(subscriber, SystemClock.uptimeMillis()); + Class<?> subscriberType = subscriber.getClass(); + ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType); + if (subscriberMethods != null) { + if (DEBUG_TRACE_ALL) { + logWithPid("Subscriber class type already registered"); + } + + // If we've parsed this subscriber type before, just add to the set for all the known + // events + for (EventHandlerMethod method : subscriberMethods) { + ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType); + eventTypeHandlers.add(new EventHandler(sub, method, priority)); + sortEventHandlersByPriority(eventTypeHandlers); + } + mSubscribers.add(sub); + return; + } else { + if (DEBUG_TRACE_ALL) { + logWithPid("Subscriber class type requires registration"); + } + + // If we are parsing this type from scratch, ensure we add it to the subscriber type + // map, and pull out he handler methods below + subscriberMethods = new ArrayList<>(); + mSubscriberTypeMap.put(subscriberType, subscriberMethods); + mSubscribers.add(sub); + } + + // Find all the valid event bus handler methods of the subscriber + MutableBoolean isInterprocessEvent = new MutableBoolean(false); + Method[] methods = subscriberType.getDeclaredMethods(); + for (Method m : methods) { + Class<?>[] parameterTypes = m.getParameterTypes(); + isInterprocessEvent.value = false; + if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) { + Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0]; + ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType); + if (eventTypeHandlers == null) { + eventTypeHandlers = new ArrayList<>(); + mEventTypeMap.put(eventType, eventTypeHandlers); + } + if (isInterprocessEvent.value) { + try { + // Enforce that the event must have a Bundle constructor + eventType.getConstructor(Bundle.class); + + mInterprocessEventNameMap.put(eventType.getName(), + (Class<? extends InterprocessEvent>) eventType); + if (hasInterprocessEventsChangedOut != null) { + hasInterprocessEventsChangedOut.value = true; + } + } catch (NoSuchMethodException e) { + throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor"); + } + } + EventHandlerMethod method = new EventHandlerMethod(m, eventType); + EventHandler handler = new EventHandler(sub, method, priority); + eventTypeHandlers.add(handler); + subscriberMethods.add(method); + sortEventHandlersByPriority(eventTypeHandlers); + + if (DEBUG_TRACE_ALL) { + logWithPid(" * Method: " + m.getName() + + " event: " + parameterTypes[0].getSimpleName() + + " interprocess? " + isInterprocessEvent.value); + } + } + } + if (DEBUG_TRACE_ALL) { + logWithPid("Registered " + subscriber.getClass().getSimpleName() + " in " + + (SystemClock.currentTimeMicro() - t1) + " microseconds"); + } + } + + /** + * Adds a new message. + */ + private void queueEvent(final Event event) { + ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass()); + if (eventHandlers == null) { + return; + } + // We need to clone the list in case a subscriber unregisters itself during traversal + eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone(); + for (final EventHandler eventHandler : eventHandlers) { + if (eventHandler.subscriber.getReference() != null) { + if (event.requiresPost) { + mHandler.post(new Runnable() { + @Override + public void run() { + processEvent(eventHandler, event); + } + }); + } else { + processEvent(eventHandler, event); + } + } + } + } + + /** + * Processes and dispatches the given event to the given event handler, on the thread of whoever + * calls this method. + */ + private void processEvent(final EventHandler eventHandler, final Event event) { + // Skip if the event was already cancelled + if (event.cancelled) { + if (event.trace || DEBUG_TRACE_ALL) { + logWithPid("Event dispatch cancelled"); + } + return; + } + + try { + if (event.trace || DEBUG_TRACE_ALL) { + logWithPid(" -> " + eventHandler.toString()); + } + Object sub = eventHandler.subscriber.getReference(); + if (sub != null) { + long t1 = 0; + if (DEBUG_TRACE_ALL) { + t1 = SystemClock.currentTimeMicro(); + } + eventHandler.method.invoke(sub, event); + if (DEBUG_TRACE_ALL) { + long duration = (SystemClock.currentTimeMicro() - t1); + mCallDurationMicros += duration; + mCallCount++; + logWithPid(eventHandler.method.toString() + " duration: " + duration + + " microseconds, avg: " + (mCallDurationMicros / mCallCount)); + } + } else { + Log.e(TAG, "Failed to deliver event to null subscriber"); + } + } catch (IllegalAccessException e) { + Log.e(TAG, "Failed to invoke method", e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + } + + /** + * Re-registers the broadcast receiver for any new messages that we want to listen for. + */ + private void registerReceiverForInterprocessEvents(Context context) { + if (DEBUG_TRACE_ALL) { + logWithPid("registerReceiverForInterprocessEvents()"); + } + // Rebuild the receiver filter with the new interprocess events + IntentFilter filter = new IntentFilter(); + for (String eventName : mInterprocessEventNameMap.keySet()) { + filter.addAction(eventName); + if (DEBUG_TRACE_ALL) { + logWithPid(" filter: " + eventName); + } + } + // Re-register the receiver with the new filter + if (mHasRegisteredReceiver) { + context.unregisterReceiver(this); + } + context.registerReceiverAsUser(this, UserHandle.ALL, filter, PERMISSION_SELF, mHandler); + mHasRegisteredReceiver = true; + } + + /** + * Returns whether this subscriber is currently registered. If {@param removeFoundSubscriber} + * is true, then remove the subscriber before returning. + */ + private boolean findRegisteredSubscriber(Object subscriber, boolean removeFoundSubscriber) { + for (int i = mSubscribers.size() - 1; i >= 0; i--) { + Subscriber sub = mSubscribers.get(i); + if (sub.getReference() == subscriber) { + if (removeFoundSubscriber) { + mSubscribers.remove(i); + } + return true; + } + } + return false; + } + + /** + * @return whether {@param method} is a valid (normal or interprocess) event bus handler method + */ + private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes, + MutableBoolean isInterprocessEventOut) { + int modifiers = method.getModifiers(); + if (Modifier.isPublic(modifiers) && + Modifier.isFinal(modifiers) && + method.getReturnType().equals(Void.TYPE) && + parameterTypes.length == 1) { + if (EventBus.InterprocessEvent.class.isAssignableFrom(parameterTypes[0]) && + method.getName().startsWith(INTERPROCESS_METHOD_PREFIX)) { + isInterprocessEventOut.value = true; + return true; + } else if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) && + method.getName().startsWith(METHOD_PREFIX)) { + isInterprocessEventOut.value = false; + return true; + } else { + if (DEBUG_TRACE_ALL) { + if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) { + logWithPid(" Expected method take an Event-based parameter: " + method.getName()); + } else if (!method.getName().startsWith(INTERPROCESS_METHOD_PREFIX) && + !method.getName().startsWith(METHOD_PREFIX)) { + logWithPid(" Expected method start with method prefix: " + method.getName()); + } + } + } + } else { + if (DEBUG_TRACE_ALL) { + if (!Modifier.isPublic(modifiers)) { + logWithPid(" Expected method to be public: " + method.getName()); + } else if (!Modifier.isFinal(modifiers)) { + logWithPid(" Expected method to be final: " + method.getName()); + } else if (!method.getReturnType().equals(Void.TYPE)) { + logWithPid(" Expected method to return null: " + method.getName()); + } + } + } + return false; + } + + /** + * Sorts the event handlers by priority and registration time. + */ + private void sortEventHandlersByPriority(List<EventHandler> eventHandlers) { + Collections.sort(eventHandlers, EVENT_HANDLER_COMPARATOR); + } + + /** + * Helper method to log the given {@param text} with the current process and user id. + */ + private static void logWithPid(String text) { + Log.d(TAG, "[" + android.os.Process.myPid() + ", u" + UserHandle.myUserId() + "] " + text); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java new file mode 100644 index 000000000000..52cfe18a9e26 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java @@ -0,0 +1,28 @@ +/* + * 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.systemui.recents.events.activity; + +import com.android.systemui.recents.RecentsAppWidgetHost; +import com.android.systemui.recents.events.EventBus; + +/** + * This is sent by the {@link RecentsAppWidgetHost} whenever the search provider widget changes, and + * subscribers can update accordingly. + */ +public class AppWidgetProviderChangedEvent extends EventBus.Event { + // Simple event +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java new file mode 100644 index 000000000000..3b68574c2830 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java @@ -0,0 +1,39 @@ +/* + * 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.systemui.recents.events.activity; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.model.RecentsPackageMonitor; +import com.android.systemui.recents.views.TaskStackView; + +/** + * This event is sent by {@link RecentsPackageMonitor} when a package on the the system changes. + * {@link TaskStackView}s listen for this event, and remove the tasks associated with the removed + * packages. + */ +public class PackagesChangedEvent extends EventBus.Event { + + public final RecentsPackageMonitor monitor; + public final String packageName; + public final int userId; + + public PackagesChangedEvent(RecentsPackageMonitor monitor, String packageName, int userId) { + this.monitor = monitor; + this.packageName = packageName; + this.userId = userId; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java new file mode 100644 index 000000000000..12e5d3d61cf7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java @@ -0,0 +1,35 @@ +/* + * 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.systemui.recents.events.ui; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.model.Task; +import com.android.systemui.recents.views.TaskView; + +/** + * This is sent when a {@link TaskView} has been dismissed. + */ +public class DismissTaskEvent extends EventBus.Event { + + public final Task task; + public final TaskView taskView; + + public DismissTaskEvent(Task task, TaskView taskView) { + this.task = task; + this.taskView = taskView; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java new file mode 100644 index 000000000000..e0d83fd847bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java @@ -0,0 +1,32 @@ +/* + * 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.systemui.recents.events.ui; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.model.Task; + +/** + * This is sent when a {@link Task} is resized. + */ +public class ResizeTaskEvent extends EventBus.Event { + + public final Task task; + + public ResizeTaskEvent(Task task) { + this.task = task; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java new file mode 100644 index 000000000000..40c30b884eae --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java @@ -0,0 +1,32 @@ +/* + * 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.systemui.recents.events.ui; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.model.Task; + +/** + * This is sent when a user wants to show the application info for a {@link Task}. + */ +public class ShowApplicationInfoEvent extends EventBus.Event { + + public final Task task; + + public ShowApplicationInfoEvent(Task task) { + this.task = task; + } +} 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 b6d25f507cb9..e0f820d400b6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -55,10 +55,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.MutableBoolean; -import android.util.MutableFloat; -import android.util.MutableInt; import android.util.Pair; -import android.util.Size; import android.view.Display; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java index e48e5f053f5f..8f9a2935c3a6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java @@ -21,6 +21,8 @@ import android.content.Context; import android.os.Looper; import android.os.UserHandle; import com.android.internal.content.PackageMonitor; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.PackagesChangedEvent; import com.android.systemui.recents.misc.SystemServicesProxy; import java.util.HashSet; @@ -31,18 +33,9 @@ import java.util.List; * Recents list. */ public class RecentsPackageMonitor extends PackageMonitor { - public interface PackageCallbacks { - public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, - int userId); - } - - PackageCallbacks mCb; - SystemServicesProxy mSystemServicesProxy; /** Registers the broadcast receivers with the specified callbacks. */ - public void register(Context context, PackageCallbacks cb) { - mSystemServicesProxy = new SystemServicesProxy(context); - mCb = cb; + public void register(Context context) { try { // We register for events from all users, but will cross-reference them with // packages for the current user and any profiles they have @@ -60,17 +53,13 @@ public class RecentsPackageMonitor extends PackageMonitor { } catch (IllegalStateException e) { e.printStackTrace(); } - mSystemServicesProxy = null; - mCb = null; } @Override public void onPackageRemoved(String packageName, int uid) { - if (mCb == null) return; - // Notify callbacks that a package has changed final int eventUserId = getChangingUserId(); - mCb.onPackagesChanged(this, packageName, eventUserId); + EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId)); } @Override @@ -81,11 +70,9 @@ public class RecentsPackageMonitor extends PackageMonitor { @Override public void onPackageModified(String packageName) { - if (mCb == null) return; - // Notify callbacks that a package has changed final int eventUserId = getChangingUserId(); - mCb.onPackagesChanged(this, packageName, eventUserId); + EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId)); } /** @@ -108,7 +95,8 @@ public class RecentsPackageMonitor extends PackageMonitor { // If we know that the component still exists in the package, then skip continue; } - if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) { + SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); + if (ssp.getActivityInfo(cn, userId) != null) { existingComponents.add(cn); } else { removedComponents.add(cn); 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 760382ed469e..39bef81386b4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -262,8 +262,6 @@ public class RecentsTaskLoader { TaskResourceLoadQueue mLoadQueue; TaskResourceLoader mLoader; - RecentsPackageMonitor mPackageMonitor; - int mMaxThumbnailCacheSize; int mMaxIconCacheSize; int mNumVisibleTasksLoaded; @@ -293,7 +291,6 @@ public class RecentsTaskLoader { // Initialize the proxy, cache and loaders mSystemServicesProxy = new SystemServicesProxy(context); - mPackageMonitor = new RecentsPackageMonitor(); mLoadQueue = new TaskResourceLoadQueue(); mApplicationIconCache = new DrawableLruCache(iconCacheSize); mThumbnailCache = new BitmapLruCache(thumbnailCacheSize); @@ -519,17 +516,6 @@ public class RecentsTaskLoader { mLoadQueue.clearTasks(); } - /** Registers any broadcast receivers. */ - public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) { - // Register the broadcast receiver to handle messages related to packages being added/removed - mPackageMonitor.register(context, cb); - } - - /** Unregisters any broadcast receivers. */ - public void unregisterReceivers() { - mPackageMonitor.unregister(); - } - /** * Handles signals from the system, trimming memory when requested to prevent us from running * out of memory. 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 20d9203ef71f..8eec87ee8f76 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -18,10 +18,10 @@ package com.android.systemui.recents.model; import android.content.Context; import android.graphics.Color; +import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.misc.NamedCounter; import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.R; import java.util.ArrayList; import java.util.Collections; 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 73c9be94eeae..de8730dd8be7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -18,18 +18,13 @@ package com.android.systemui.recents.views; import android.app.ActivityManager; import android.app.ActivityOptions; -import android.app.TaskStackBuilder; import android.content.Context; -import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; -import android.net.Uri; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.RemoteException; -import android.os.UserHandle; -import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -46,8 +41,9 @@ import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsAppWidgetHostView; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.ui.DismissTaskEvent; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.RecentsPackageMonitor; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -59,8 +55,7 @@ import java.util.List; * This view is the the top level layout that contains TaskStacks (which are laid out according * to their SpaceNode bounds. */ -public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks, - RecentsPackageMonitor.PackageCallbacks { +public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks { private static final String TAG = "RecentsView"; @@ -73,7 +68,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV public void onAllTaskViewsDismissed(); public void onExitToHomeAnimationTriggered(); public void onScreenPinningRequest(); - public void onTaskResize(Task t); public void runAfterPause(Runnable r); } @@ -611,7 +605,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } else { // Dismiss the task and return the user to home if we fail to // launch the task - onTaskViewDismissed(task); + EventBus.getDefault().send(new DismissTaskEvent(task, tv)); if (mCb != null) { mCb.onTaskLaunchFailed(); } @@ -648,37 +642,15 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } @Override - public void onTaskViewAppInfoClicked(Task t) { - // Create a new task stack with the application info details activity - Intent baseIntent = t.key.baseIntent; - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null)); - intent.setComponent(intent.resolveActivity(getContext().getPackageManager())); - TaskStackBuilder.create(getContext()) - .addNextIntentWithParentStack(intent).startActivities(null, - new UserHandle(t.key.userId)); - } - - @Override - public void onTaskViewDismissed(Task t) { - // Remove any stored data from the loader. We currently don't bother notifying the views - // that the data has been unloaded because at the point we call onTaskViewDismissed(), the views - // either don't need to be updated, or have already been removed. - RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); - loader.deleteTaskData(t, false); - - // Remove the old task from activity manager - loader.getSystemServicesProxy().removeTask(t.key.id); - } - - @Override public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks) { + /* TODO: Not currently enabled if (removedTasks != null) { int taskCount = removedTasks.size(); for (int i = 0; i < taskCount; i++) { onTaskViewDismissed(removedTasks.get(i)); } } + */ mCb.onAllTaskViewsDismissed(); @@ -725,21 +697,4 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV .start(); } } - - @Override - public void onTaskResize(Task t) { - if (mCb != null) { - mCb.onTaskResize(t); - } - } - - /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ - - @Override - public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) { - // Propagate this event down to each task stack view - if (mTaskStackView != null) { - mTaskStackView.onPackagesChanged(monitor, packageName, userId); - } - } } 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 7ce50d803ee2..b28cc21737e4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -22,7 +22,6 @@ import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.systemui.R; -import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; 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 b5f29a01c2b0..67e3f8271132 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -29,15 +29,17 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; -import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Constants; +import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.PackagesChangedEvent; +import com.android.systemui.recents.events.ui.DismissTaskEvent; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.model.RecentsPackageMonitor; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -54,19 +56,15 @@ import java.util.List; /* The visual representation of a task stack view */ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks, TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks, - ViewPool.ViewPoolConsumer<TaskView, Task>, RecentsPackageMonitor.PackageCallbacks { + ViewPool.ViewPoolConsumer<TaskView, Task> { /** The TaskView callbacks */ interface TaskStackViewCallbacks { public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t, boolean lockToTask, boolean boundsValid, Rect bounds); - public void onTaskViewAppInfoClicked(Task t); - public void onTaskViewDismissed(Task t); public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks); public void onTaskStackFilterTriggered(); public void onTaskStackUnfilterTriggered(); - - public void onTaskResize(Task t); } RecentsConfiguration mConfig; @@ -77,7 +75,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskStackViewTouchHandler mTouchHandler; TaskStackViewCallbacks mCb; ViewPool<TaskView, Task> mViewPool; - ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>(); + ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>(); DozeTrigger mUIDozeTrigger; DismissView mDismissAllButton; boolean mDismissAllButtonAnimating; @@ -97,9 +95,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Matrix mTmpMatrix = new Matrix(); Rect mTmpRect = new Rect(); TaskViewTransform mTmpTransform = new TaskViewTransform(); - HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>(); - ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>(); - List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>(); + HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>(); + ArrayList<TaskView> mTaskViews = new ArrayList<>(); + List<TaskView> mImmutableTaskViews = new ArrayList<>(); LayoutInflater mInflater; boolean mLayersDisabled; @@ -147,6 +145,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mCb = cb; } + @Override + protected void onAttachedToWindow() { + EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1); + super.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + EventBus.getDefault().unregister(this); + } + /** Sets the task stack */ void setStack(TaskStack stack) { // Set the new stack @@ -1161,11 +1171,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Fade the dismiss button back in showDismissAllButton(); } - - // Notify the callback that we've removed the task and it can clean up after it. Note, we - // do this after onAllTaskViewsDismissed() is called, to allow the home activity to be - // started before the call to remove the task. - mCb.onTaskViewDismissed(removedTask); } @Override @@ -1343,27 +1348,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /**** TaskViewCallbacks Implementation ****/ @Override - public void onTaskViewAppIconClicked(TaskView tv) { - if (Constants.DebugFlags.App.EnableTaskFiltering) { - if (mStack.hasFilteredTasks()) { - mStack.unfilterTasks(); - } else { - mStack.filterTasks(tv.getTask()); - } - } - } - - @Override - public void onTaskViewAppInfoClicked(TaskView tv) { - if (mCb != null) { - mCb.onTaskViewAppInfoClicked(tv.getTask()); - - // Keep track of app-info invocations - MetricsLogger.count(getContext(), "overview_app_info", 1); - } - } - - @Override public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask) { // Cancel any doze triggers mUIDozeTrigger.stopDozing(); @@ -1374,33 +1358,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override - public void onTaskViewDismissed(TaskView tv) { - Task task = tv.getTask(); - int taskIndex = mStack.indexOfTask(task); - boolean taskWasFocused = tv.isFocusedTask(); - // Announce for accessibility - tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed, - tv.getTask().activityLabel)); - // Remove the task from the view - mStack.removeTask(task); - // If the dismissed task was focused, then we should focus the new task in the same index - if (taskWasFocused) { - ArrayList<Task> tasks = mStack.getTasks(); - int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1); - if (nextTaskIndex >= 0) { - Task nextTask = tasks.get(nextTaskIndex); - TaskView nextTv = getChildViewForTask(nextTask); - if (nextTv != null) { - // Focus the next task, and only animate the visible state if we are launched - // from Alt-Tab - RecentsActivityLaunchState launchState = mConfig.getLaunchState(); - nextTv.setFocusedTask(launchState.launchedWithAltTab); - } - } - } - } - - @Override public void onTaskViewClipStateChanged(TaskView tv) { if (!mStackViewsDirty) { invalidate(); @@ -1414,13 +1371,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - @Override - public void onTaskResize(TaskView tv) { - if (mCb != null) { - mCb.onTaskResize(tv.getTask()); - } - } - /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/ @Override @@ -1430,13 +1380,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal postInvalidateOnAnimation(); } - /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ + /**** EventBus Events ****/ - @Override - public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) { + public final void onBusEvent(PackagesChangedEvent event) { // Compute which components need to be removed - HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved( - mStack.getTaskKeys(), packageName, userId); + HashSet<ComponentName> removedComponents = event.monitor.computeComponentsRemoved( + mStack.getTaskKeys(), event.packageName, event.userId); // For other tasks, just remove them directly if they no longer exist ArrayList<Task> tasks = mStack.getTasks(); @@ -1459,4 +1408,33 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } } + + public final void onBusEvent(DismissTaskEvent event) { + TaskView tv = event.taskView; + Task task = tv.getTask(); + int taskIndex = mStack.indexOfTask(task); + boolean taskWasFocused = tv.isFocusedTask(); + + // Announce for accessibility + tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed, + tv.getTask().activityLabel)); + + // Remove the task from the view + mStack.removeTask(task); + // If the dismissed task was focused, then we should focus the new task in the same index + if (taskWasFocused) { + ArrayList<Task> tasks = mStack.getTasks(); + int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1); + if (nextTaskIndex >= 0) { + Task nextTask = tasks.get(nextTaskIndex); + TaskView nextTv = getChildViewForTask(nextTask); + if (nextTv != null) { + // Focus the next task, and only animate the visible state if we are launched + // from Alt-Tab + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + nextTv.setFocusedTask(launchState.launchedWithAltTab); + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java index e9f6a46c9707..a32b2422aa24 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java @@ -16,9 +16,9 @@ package com.android.systemui.recents.views; +import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.model.Task; -import com.android.systemui.R; import java.util.ArrayList; import java.util.HashMap; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java index 7f4c0a5f7cb4..a8e6f4703177 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -18,11 +18,11 @@ package com.android.systemui.recents.views; import android.content.Context; import android.graphics.Rect; +import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; -import com.android.systemui.R; import java.util.ArrayList; import java.util.HashMap; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java index f0ae87f6f9ae..e4fbc76f9d3b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -24,8 +24,8 @@ import android.content.Context; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.OverScroller; -import com.android.systemui.recents.misc.Utilities; import com.android.systemui.R; +import com.android.systemui.recents.misc.Utilities; /* The scrolling logic for a TaskStackView */ public class TaskStackViewScroller { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index 86eced8a763d..48c5b46c34d7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -24,9 +24,11 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewParent; import com.android.internal.logging.MetricsLogger; +import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; -import com.android.systemui.R; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.ui.DismissTaskEvent; import java.util.List; @@ -435,7 +437,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // Re-enable touch events from this task view tv.setTouchEnabled(true); // Remove the task view from the stack - mSv.onTaskViewDismissed(tv); + EventBus.getDefault().send(new DismissTaskEvent(tv.getTask(), tv)); // Keep track of deletions by keyboard MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source", Constants.Metrics.DismissSourceSwipeGesture); 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 bbbaccf3fa5f..910db873e0b9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -30,34 +30,29 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; -import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; -import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.ui.DismissTaskEvent; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.statusbar.phone.PhoneStatusBar; /* A task view */ public class TaskView extends FrameLayout implements Task.TaskCallbacks, - View.OnClickListener, View.OnLongClickListener { + View.OnClickListener { /** The TaskView callbacks */ interface TaskViewCallbacks { - public void onTaskViewAppIconClicked(TaskView tv); - public void onTaskViewAppInfoClicked(TaskView tv); public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask); - public void onTaskViewDismissed(TaskView tv); public void onTaskViewClipStateChanged(TaskView tv); public void onTaskViewFocusChanged(TaskView tv, boolean focused); - - public void onTaskResize(TaskView tv); } RecentsConfiguration mConfig; @@ -535,9 +530,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, startDeleteTaskAnimation(new Runnable() { @Override public void run() { - if (mCb != null) { - mCb.onTaskViewDismissed(tv); - } + EventBus.getDefault().send(new DismissTaskEvent(mTask, tv)); } }, 0); } @@ -725,17 +718,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mThumbnailView.rebindToTask(mTask); mHeaderView.rebindToTask(mTask); // Rebind any listeners - AccessibilityManager am = (AccessibilityManager) getContext(). - getSystemService(Context.ACCESSIBILITY_SERVICE); - if (Constants.DebugFlags.App.EnableTaskFiltering || (am != null && am.isEnabled())) { - mHeaderView.mApplicationIcon.setOnClickListener(this); - } - mHeaderView.mDismissButton.setOnClickListener(this); - if (mConfig.multiWindowEnabled) { - mHeaderView.mMoveTaskButton.setOnClickListener(this); - } mActionButtonView.setOnClickListener(this); - mHeaderView.mApplicationIcon.setOnLongClickListener(this); } mTaskDataLoaded = true; } @@ -748,13 +731,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mThumbnailView.unbindFromTask(); mHeaderView.unbindFromTask(); // Unbind any listeners - mHeaderView.mApplicationIcon.setOnClickListener(null); - mHeaderView.mDismissButton.setOnClickListener(null); - if (mConfig.multiWindowEnabled) { - mHeaderView.mMoveTaskButton.setOnClickListener(null); - } mActionButtonView.setOnClickListener(null); - mHeaderView.mApplicationIcon.setOnLongClickListener(null); } mTaskDataLoaded = false; } @@ -768,60 +745,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, @Override public void onClick(final View v) { - final TaskView tv = this; - final boolean delayViewClick = (v != this) && (v != mActionButtonView); - if (delayViewClick) { - // We purposely post the handler delayed to allow for the touch feedback to draw - postDelayed(new Runnable() { - @Override - public void run() { - if (v == mHeaderView.mApplicationIcon) { - if (Constants.DebugFlags.App.EnableTaskFiltering) { - if (mCb != null) { - mCb.onTaskViewAppIconClicked(tv); - } - } else { - AccessibilityManager am = (AccessibilityManager) getContext(). - getSystemService(Context.ACCESSIBILITY_SERVICE); - if (am != null && am.isEnabled()) { - if (mCb != null) { - mCb.onTaskViewAppInfoClicked(tv); - } - } - } - } else if (v == mHeaderView.mDismissButton) { - dismissTask(); - // Keep track of deletions by the dismiss button - MetricsLogger.histogram(getContext(), "overview_task_dismissed_source", - Constants.Metrics.DismissSourceHeaderButton); - } else if (v == mHeaderView.mMoveTaskButton) { - if (mCb != null) { - mCb.onTaskResize(tv); - } - } - } - }, 125); - } else { - if (v == mActionButtonView) { - // Reset the translation of the action button before we animate it out - mActionButtonView.setTranslationZ(0f); - } - if (mCb != null) { - mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView)); - } + if (v == mActionButtonView) { + // Reset the translation of the action button before we animate it out + mActionButtonView.setTranslationZ(0f); } - } - - /**** View.OnLongClickListener Implementation ****/ - - @Override - public boolean onLongClick(View v) { - if (v == mHeaderView.mApplicationIcon) { - if (mCb != null) { - mCb.onTaskViewAppInfoClicked(this); - return true; - } + if (mCb != null) { + mCb.onTaskViewClicked(this, mTask, (v == mActionButtonView)); } - return false; } } 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 f68dd64b0bf2..7de8b7be5134 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -39,14 +39,19 @@ import android.graphics.drawable.RippleDrawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.ui.ResizeTaskEvent; +import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.RecentsTaskLoader; @@ -54,10 +59,12 @@ import com.android.systemui.recents.model.Task; /* The task bar view */ -public class TaskViewHeader extends FrameLayout { +public class TaskViewHeader extends FrameLayout + implements View.OnClickListener, View.OnLongClickListener { RecentsConfiguration mConfig; private SystemServicesProxy mSsp; + Task mTask; // Header views ImageView mMoveTaskButton; @@ -144,15 +151,15 @@ public class TaskViewHeader extends FrameLayout { protected void onFinishInflate() { // Initialize the icon and description views mApplicationIcon = (ImageView) findViewById(R.id.application_icon); + mApplicationIcon.setOnLongClickListener(this); mActivityDescription = (TextView) findViewById(R.id.activity_description); mDismissButton = (ImageView) findViewById(R.id.dismiss_task); + mDismissButton.setOnClickListener(this); mMoveTaskButton = (ImageView) findViewById(R.id.move_task); // Hide the backgrounds if they are ripple drawables - if (!Constants.DebugFlags.App.EnableTaskFiltering) { - if (mApplicationIcon.getBackground() instanceof RippleDrawable) { - mApplicationIcon.setBackground(null); - } + if (mApplicationIcon.getBackground() instanceof RippleDrawable) { + mApplicationIcon.setBackground(null); } mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(R.drawable @@ -203,6 +210,8 @@ public class TaskViewHeader extends FrameLayout { /** Binds the bar view to the task */ public void rebindToTask(Task t) { + mTask = t; + // If an activity icon is defined, then we use that as the primary icon to show in the bar, // otherwise, we fall back to the application icon if (t.activityIcon != null) { @@ -238,6 +247,25 @@ public class TaskViewHeader extends FrameLayout { mMoveTaskButton.setVisibility((mConfig.multiWindowEnabled) ? View.VISIBLE : View.INVISIBLE); if (mConfig.multiWindowEnabled) { updateResizeTaskBarIcon(t); + mMoveTaskButton.setOnClickListener(this); + } + + // In accessibility, a single click on the focused app info button will show it + AccessibilityManager am = (AccessibilityManager) getContext(). + getSystemService(Context.ACCESSIBILITY_SERVICE); + if (am != null && am.isEnabled()) { + mApplicationIcon.setOnClickListener(this); + } + } + + /** Unbinds the bar view from the task */ + void unbindFromTask() { + mTask = null; + mApplicationIcon.setImageDrawable(null); + mApplicationIcon.setOnClickListener(null); + + if (mConfig.multiWindowEnabled) { + mMoveTaskButton.setOnClickListener(null); } } @@ -274,11 +302,6 @@ public class TaskViewHeader extends FrameLayout { mMoveTaskButton.setImageResource(resId); } - /** Unbinds the bar view from the task */ - void unbindFromTask() { - mApplicationIcon.setImageDrawable(null); - } - /** Animates this task bar dismiss button when launching a task. */ void startLaunchTaskDismissAnimation() { if (mDismissButton.getVisibility() == View.VISIBLE) { @@ -441,4 +464,30 @@ public class TaskViewHeader extends FrameLayout { } } } + + @Override + public void onClick(View v) { + if (v == mApplicationIcon) { + // In accessibility, a single click on the focused app info button will show it + EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask)); + } else if (v == mDismissButton) { + TaskView tv = (TaskView) getParent().getParent(); + tv.dismissTask(); + + // Keep track of deletions by the dismiss button + MetricsLogger.histogram(getContext(), "overview_task_dismissed_source", + Constants.Metrics.DismissSourceHeaderButton); + } else if (v == mMoveTaskButton) { + EventBus.getDefault().send(new ResizeTaskEvent(mTask)); + } + } + + @Override + public boolean onLongClick(View v) { + if (v == mApplicationIcon) { + EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask)); + return true; + } + return false; + } } 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 6c83beeff1da..690c297da964 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -34,9 +34,9 @@ import android.util.AttributeSet; import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import com.android.systemui.R; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; -import com.android.systemui.R; /** diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index a2967e8a2c47..5a27301badcb 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -1583,9 +1583,16 @@ public class RenderScript { nContextDeinitToClient(mContext); mMessageThread.mRun = false; - try { - mMessageThread.join(); - } catch(InterruptedException e) { + + // Wait for mMessageThread to join. Try in a loop, in case this thread gets interrupted + // during the wait. + boolean hasJoined = false; + while (!hasJoined) { + try { + mMessageThread.join(); + hasJoined = true; + } catch(InterruptedException e) { + } } nContextDestroy(); diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java index 32833785a186..892e9da46a3d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java @@ -32,6 +32,7 @@ import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; /** * Implements "Automatically click on mouse stop" feature. @@ -56,8 +57,6 @@ import android.view.accessibility.AccessibilityEvent; */ public class AutoclickController implements EventStreamTransformation { - public static final int DEFAULT_CLICK_DELAY_MS = 600; - private static final String LOG_TAG = AutoclickController.class.getSimpleName(); private EventStreamTransformation mNext; @@ -78,7 +77,8 @@ public class AutoclickController implements EventStreamTransformation { if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { if (mClickScheduler == null) { Handler handler = new Handler(mContext.getMainLooper()); - mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS); + mClickScheduler = + new ClickScheduler(handler, AccessibilityManager.AUTOCLICK_DELAY_DEFAULT); mClickDelayObserver = new ClickDelayObserver(mUserId, handler); mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler); } @@ -230,7 +230,7 @@ public class AutoclickController implements EventStreamTransformation { if (mAutoclickDelaySettingUri.equals(uri)) { int delay = Settings.Secure.getIntForUser( mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, - DEFAULT_CLICK_DELAY_MS, mUserId); + AccessibilityManager.AUTOCLICK_DELAY_DEFAULT, mUserId); mClickScheduler.updateDelay(delay); } } diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index c3f5c43daeb7..f6b32f7a32ec 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -112,12 +112,6 @@ class TouchExplorer implements EventStreamTransformation { // Timeout before trying to decide what the user is trying to do. private final int mDetermineUserIntentTimeout; - // Timeout within which we try to detect a tap. - private final int mTapTimeout; - - // Slop between the down and up tap to be a tap. - private final int mTouchSlop; - // Slop between the first and second tap to be a double tap. private final int mDoubleTapSlop; @@ -142,9 +136,6 @@ class TouchExplorer implements EventStreamTransformation { // Command for delayed sending of touch interaction end events. private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed; - // Command for delayed sending of a long press. - private final PerformLongPressDelayed mPerformLongPressDelayed; - // Command for exiting gesture detection mode after a timeout. private final ExitGestureDetectionModeDelayed mExitGestureDetectionModeDelayed; @@ -173,9 +164,6 @@ class TouchExplorer implements EventStreamTransformation { // Handle to the accessibility manager service. private final AccessibilityManagerService mAms; - // Temporary rectangle to avoid instantiation. - private final Rect mTempRect = new Rect(); - // Temporary point to avoid instantiation. private final Point mTempPoint = new Point(); @@ -226,12 +214,9 @@ class TouchExplorer implements EventStreamTransformation { mAms = service; mReceivedPointerTracker = new ReceivedPointerTracker(); mInjectedPointerTracker = new InjectedPointerTracker(); - mTapTimeout = ViewConfiguration.getTapTimeout(); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); mHandler = new Handler(context.getMainLooper()); - mPerformLongPressDelayed = new PerformLongPressDelayed(); mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed(); mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures); mGestureLibrary.setOrientationStyle(8); @@ -299,7 +284,6 @@ class TouchExplorer implements EventStreamTransformation { // Remove all pending callbacks. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); mExitGestureDetectionModeDelayed.cancel(); mSendTouchExplorationEndDelayed.cancel(); mSendTouchInteractionEndDelayed.cancel(); @@ -437,7 +421,6 @@ class TouchExplorer implements EventStreamTransformation { // we resent the delayed callback and wait again. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); if (mSendTouchExplorationEndDelayed.isPending()) { mSendTouchExplorationEndDelayed.forceSendAndRemove(); @@ -447,18 +430,7 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed.forceSendAndRemove(); } - // If we have the first tap, schedule a long press and break - // since we do not want to schedule hover enter because - // the delayed callback will kick in before the long click. - // This would lead to a state transition resulting in long - // pressing the item below the double taped area which is - // not necessary where accessibility focus is. - if (mDoubleTapDetector.firstTapDetected()) { - // We got a tap now post a long press action. - mPerformLongPressDelayed.post(event, policyFlags); - break; - } - if (!mTouchExplorationInProgress) { + if (!mDoubleTapDetector.firstTapDetected() && !mTouchExplorationInProgress) { if (!mSendHoverEnterAndMoveDelayed.isPending()) { // Deliver hover enter with a delay to have a chance // to detect what the user is trying to do. @@ -478,7 +450,6 @@ class TouchExplorer implements EventStreamTransformation { // decide what we will actually do next. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); } break; case MotionEvent.ACTION_MOVE: { final int pointerId = receivedTracker.getPrimaryPointerId(); @@ -521,7 +492,6 @@ class TouchExplorer implements EventStreamTransformation { mVelocityTracker.clear(); mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); mExitGestureDetectionModeDelayed.post(); // Send accessibility event to announce the start // of gesture recognition. @@ -532,28 +502,12 @@ class TouchExplorer implements EventStreamTransformation { // exploring so start sending events. mSendHoverEnterAndMoveDelayed.forceSendAndRemove(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags); } break; } } else { - // Cancel the long press if pending and the user - // moved more than the slop. - if (mPerformLongPressDelayed.isPending()) { - final float deltaX = - receivedTracker.getReceivedPointerDownX(pointerId) - - rawEvent.getX(pointerIndex); - final float deltaY = - receivedTracker.getReceivedPointerDownY(pointerId) - - rawEvent.getY(pointerIndex); - final double moveDelta = Math.hypot(deltaX, deltaY); - // The user has moved enough for us to decide. - if (moveDelta > mTouchSlop) { - mPerformLongPressDelayed.cancel(); - } - } if (mTouchExplorationInProgress) { sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags); sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, @@ -569,9 +523,7 @@ class TouchExplorer implements EventStreamTransformation { // scheduled sending events. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); } else { - mPerformLongPressDelayed.cancel(); if (mTouchExplorationInProgress) { // If the user is touch exploring the second pointer may be // performing a double tap to activate an item without need @@ -620,9 +572,7 @@ class TouchExplorer implements EventStreamTransformation { // scheduled sending events. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); } else { - mPerformLongPressDelayed.cancel(); // We are sending events so send exit and gesture // end since we transition to another state. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); @@ -643,7 +593,6 @@ class TouchExplorer implements EventStreamTransformation { final int pointerId = event.getPointerId(event.getActionIndex()); final int pointerIdBits = (1 << pointerId); - mPerformLongPressDelayed.cancel(); mVelocityTracker.clear(); if (mSendHoverEnterAndMoveDelayed.isPending()) { @@ -1110,6 +1059,7 @@ class TouchExplorer implements EventStreamTransformation { private final GestureDetector mGestureDetector; private boolean mFirstTapDetected; private boolean mDoubleTapDetected; + private int mPolicyFlags; DoubleTapDetector(Context context) { mGestureDetector = new GestureDetector(context, this); @@ -1117,6 +1067,7 @@ class TouchExplorer implements EventStreamTransformation { } public void onMotionEvent(MotionEvent event, int policyFlags) { + mPolicyFlags = policyFlags; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mDoubleTapDetected = false; @@ -1135,6 +1086,11 @@ class TouchExplorer implements EventStreamTransformation { } @Override + public void onLongPress(MotionEvent e) { + maybeSendLongPress(e, mPolicyFlags); + } + + @Override public boolean onSingleTapUp(MotionEvent event) { mFirstTapDetected = true; return false; @@ -1154,6 +1110,38 @@ class TouchExplorer implements EventStreamTransformation { return true; } + private void maybeSendLongPress(MotionEvent event, int policyFlags) { + if (!mDoubleTapDetected) { + return; + } + + clear(); + + // Pointers should not be zero when running this command. + if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) { + return; + } + + final int pointerIndex = event.getActionIndex(); + final int pointerId = event.getPointerId(pointerIndex); + + Point clickLocation = mTempPoint; + final int result = computeClickLocation(clickLocation); + + if (result == CLICK_LOCATION_NONE) { + return; + } + + mLongPressingPointerId = pointerId; + mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x; + mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y; + + sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); + + mCurrentState = STATE_DELEGATING; + sendDownForAllNotInjectedPointers(event, policyFlags); + } + private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) { if (!mDoubleTapDetected) { return; @@ -1169,7 +1157,6 @@ class TouchExplorer implements EventStreamTransformation { // Remove pending event deliveries. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - mPerformLongPressDelayed.cancel(); if (mSendTouchExplorationEndDelayed.isPending()) { mSendTouchExplorationEndDelayed.forceSendAndRemove(); @@ -1178,8 +1165,8 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed.forceSendAndRemove(); } - final int pointerId = event.getPointerId(event.getActionIndex()); - final int pointerIndex = event.findPointerIndex(pointerId); + final int pointerIndex = event.getActionIndex(); + final int pointerId = event.getPointerId(pointerIndex); Point clickLocation = mTempPoint; final int result = computeClickLocation(clickLocation); @@ -1306,65 +1293,6 @@ class TouchExplorer implements EventStreamTransformation { } /** - * Class for delayed sending of long press. - */ - private final class PerformLongPressDelayed implements Runnable { - private MotionEvent mEvent; - private int mPolicyFlags; - - public void post(MotionEvent prototype, int policyFlags) { - mEvent = MotionEvent.obtain(prototype); - mPolicyFlags = policyFlags; - mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout()); - } - - public void cancel() { - if (mEvent != null) { - mHandler.removeCallbacks(this); - clear(); - } - } - - private boolean isPending() { - return mHandler.hasCallbacks(this); - } - - @Override - public void run() { - // Pointers should not be zero when running this command. - if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) { - return; - } - - final int pointerId = mEvent.getPointerId(mEvent.getActionIndex()); - final int pointerIndex = mEvent.findPointerIndex(pointerId); - - Point clickLocation = mTempPoint; - final int result = computeClickLocation(clickLocation); - - if (result == CLICK_LOCATION_NONE) { - return; - } - - mLongPressingPointerId = pointerId; - mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocation.x; - mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocation.y; - - sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags); - - mCurrentState = STATE_DELEGATING; - sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags); - clear(); - } - - private void clear() { - mEvent.recycle(); - mEvent = null; - mPolicyFlags = 0; - } - } - - /** * Class for delayed sending of hover enter and move events. */ class SendHoverEnterAndMoveDelayed implements Runnable { diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index f2459852d706..2aa039064410 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -55,7 +55,8 @@ public class GestureLauncherService extends SystemService { * Time in milliseconds in which the power button must be pressed twice so it will be considered * as a camera launch. */ - private static final long CAMERA_POWER_DOUBLE_TAP_TIME_MS = 300; + private static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300; + private static final long CAMERA_POWER_DOUBLE_TAP_MIN_TIME_MS = 120; /** The listener that receives the gesture event. */ private final GestureEventListener mGestureListener = new GestureEventListener(); @@ -256,14 +257,16 @@ public class GestureLauncherService extends SystemService { synchronized (this) { doubleTapInterval = event.getEventTime() - mLastPowerDown; if (mCameraDoubleTapPowerEnabled - && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_TIME_MS) { + && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS + && doubleTapInterval > CAMERA_POWER_DOUBLE_TAP_MIN_TIME_MS) { launched = true; intercept = interactive; } mLastPowerDown = event.getEventTime(); } if (launched) { - Slog.i(TAG, "Power button double tap gesture detected, launching camera."); + Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval=" + + doubleTapInterval + "ms"); launched = handleCameraLaunchGesture(false /* useWakelock */, StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP); if (launched) { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 9dad7a181a06..ab1d775e3c32 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -37,6 +37,7 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManagerNative; import android.app.AlertDialog; import android.app.AppGlobals; @@ -280,8 +281,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean mSystemReady; /** - * Id of the currently selected input method. + * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method. + * method. This is to be synchronized with the secure settings keyed with + * {@link Settings.Secure#DEFAULT_INPUT_METHOD}. + * + * <p>This can be transiently {@code null} when the system is re-initializing input method + * settings, e.g., the system locale is just changed.</p> + * + * <p>Note that {@link #mCurId} is used to track which IME is being connected to + * {@link InputMethodManagerService}.</p> + * + * @see #mCurId */ + @Nullable String mCurMethodId; /** @@ -311,9 +323,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub EditorInfo mCurAttribute; /** - * The input method ID of the input method service that we are currently + * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently * connected to or in the process of connecting to. + * + * <p>This can be {@code null} when no input method is connected.</p> + * + * @see #mCurMethodId */ + @Nullable String mCurId; /** @@ -918,7 +935,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub || (newLocale != null && !newLocale.equals(mLastSystemLocale))) { if (!updateOnlyWhenLocaleChanged) { hideCurrentInputLocked(0, null); - mCurMethodId = null; unbindCurrentMethodLocked(true, false); } if (DEBUG) { @@ -1474,7 +1490,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub channel.dispose(); } - void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) { + void unbindCurrentMethodLocked(boolean resetCurrentMethodAndClient, boolean savePosition) { + if (resetCurrentMethodAndClient) { + mCurMethodId = null; + } + if (mVisibleBound) { mContext.unbindService(mVisibleConnection); mVisibleBound = false; @@ -1501,9 +1521,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurId = null; clearCurMethodLocked(); - if (reportToClient && mCurClient != null) { - executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO( - MSG_UNBIND_METHOD, mCurSeq, mCurClient.client)); + if (resetCurrentMethodAndClient) { + unbindCurrentClientLocked(); } } @@ -1857,13 +1876,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id)); } catch (IllegalArgumentException e) { Slog.w(TAG, "Unknown input method from prefs: " + id, e); - mCurMethodId = null; unbindCurrentMethodLocked(true, false); } mShortcutInputMethodsAndSubtypes.clear(); } else { // There is no longer an input method set, so stop any current one. - mCurMethodId = null; unbindCurrentMethodLocked(true, false); } // Here is not the perfect place to reset the switching controller. Ideally diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index c3d32c2a870b..4d325991c8d9 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -29,6 +29,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.IActivityManager; @@ -90,7 +91,6 @@ import libcore.io.IoUtils; import libcore.util.EmptyArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IMediaContainerService; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; @@ -290,7 +290,7 @@ class MountService extends IMountService.Stub private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>(); /** Map from volume ID to disk */ @GuardedBy("mLock") - private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>(); + private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>(); /** Map from UUID to record */ @GuardedBy("mLock") @@ -462,11 +462,7 @@ class MountService extends IMountService.Stub public ObbState(String rawPath, String canonicalPath, int callingUid, IObbActionListener token, int nonce) { this.rawPath = rawPath; - this.canonicalPath = canonicalPath.toString(); - - final int userId = UserHandle.getUserId(callingUid); - this.ownerPath = buildObbPath(canonicalPath, userId, false); - this.voldPath = buildObbPath(canonicalPath, userId, true); + this.canonicalPath = canonicalPath; this.ownerGid = UserHandle.getSharedAppGid(callingUid); this.token = token; @@ -475,8 +471,6 @@ class MountService extends IMountService.Stub final String rawPath; final String canonicalPath; - final String ownerPath; - final String voldPath; final int ownerGid; @@ -509,8 +503,6 @@ class MountService extends IMountService.Stub StringBuilder sb = new StringBuilder("ObbState{"); sb.append("rawPath=").append(rawPath); sb.append(",canonicalPath=").append(canonicalPath); - sb.append(",ownerPath=").append(ownerPath); - sb.append(",voldPath=").append(voldPath); sb.append(",ownerGid=").append(ownerGid); sb.append(",token=").append(token); sb.append(",binder=").append(getBinder()); @@ -569,6 +561,7 @@ class MountService extends IMountService.Stub private static final int H_VOLUME_MOUNT = 5; private static final int H_VOLUME_BROADCAST = 6; private static final int H_INTERNAL_BROADCAST = 7; + private static final int H_VOLUME_UNMOUNT = 8; class MountServiceHandler extends Handler { public MountServiceHandler(Looper looper) { @@ -649,6 +642,11 @@ class MountService extends IMountService.Stub } break; } + case H_VOLUME_UNMOUNT: { + final VolumeInfo vol = (VolumeInfo) msg.obj; + unmount(vol.getId()); + break; + } case H_VOLUME_BROADCAST: { final StorageVolume userVol = (StorageVolume) msg.obj; final String envState = userVol.getState(); @@ -683,6 +681,7 @@ class MountService extends IMountService.Stub public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + Preconditions.checkArgument(userId >= 0); try { if (Intent.ACTION_USER_ADDED.equals(action)) { @@ -690,6 +689,16 @@ class MountService extends IMountService.Stub final int userSerialNumber = um.getUserSerialNumber(userId); mConnector.execute("volume", "user_added", userId, userSerialNumber); } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + synchronized (mVolumes) { + final int size = mVolumes.size(); + for (int i = 0; i < size; i++) { + final VolumeInfo vol = mVolumes.valueAt(i); + if (vol.mountUserId == userId) { + vol.mountUserId = UserHandle.USER_NULL; + mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget(); + } + } + } mConnector.execute("volume", "user_removed", userId); } } catch (NativeDaemonConnectorException e) { @@ -757,17 +766,26 @@ class MountService extends IMountService.Stub * paths never changing, so we outright kill them to pick up new state. */ @Deprecated - private void killMediaProvider() { + private void killMediaProvider(List<UserInfo> users) { + if (users == null) return; + final long token = Binder.clearCallingIdentity(); try { - final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, - UserHandle.USER_OWNER); - if (provider != null) { - final IActivityManager am = ActivityManagerNative.getDefault(); - try { - am.killApplicationWithAppId(provider.applicationInfo.packageName, - UserHandle.getAppId(provider.applicationInfo.uid), "vold reset"); - } catch (RemoteException e) { + for (UserInfo user : users) { + // System user does not have media provider, so skip. + if (user.isSystemOnly()) continue; + + final ProviderInfo provider = + mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id); + if (provider != null) { + final IActivityManager am = ActivityManagerNative.getDefault(); + try { + am.killApplicationWithAppId(provider.applicationInfo.packageName, + UserHandle.getAppId(provider.applicationInfo.uid), "vold reset"); + // We only need to run this once. It will kill all users' media processes. + break; + } catch (RemoteException e) { + } } } } finally { @@ -788,7 +806,9 @@ class MountService extends IMountService.Stub Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady + ", mDaemonConnected=" + mDaemonConnected); if (mSystemReady && mDaemonConnected) { - killMediaProvider(); + final UserManager um = UserManager.get(mContext); + final List<UserInfo> users = um.getUsers(); + killMediaProvider(users); mDisks.clear(); mVolumes.clear(); @@ -799,8 +819,6 @@ class MountService extends IMountService.Stub mConnector.execute("volume", "reset"); // Tell vold about all existing and started users - final UserManager um = mContext.getSystemService(UserManager.class); - final List<UserInfo> users = um.getUsers(); for (UserInfo user : users) { mConnector.execute("volume", "user_added", user.id, user.serialNumber); } @@ -1192,7 +1210,7 @@ class MountService extends IMountService.Stub vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; } - vol.mountUserId = UserHandle.USER_OWNER; + vol.mountUserId = ActivityManager.getCurrentUser(); mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else if (vol.type == VolumeInfo.TYPE_PRIVATE) { @@ -2285,7 +2303,7 @@ class MountService extends IMountService.Stub final NativeDaemonEvent event; try { - event = mConnector.execute("obb", "path", state.voldPath); + event = mConnector.execute("obb", "path", state.canonicalPath); event.checkCode(VoldResponseCode.AsecPathResult); return event.getMessage(); } catch (NativeDaemonConnectorException e) { @@ -3038,14 +3056,14 @@ class MountService extends IMountService.Stub protected ObbInfo getObbInfo() throws IOException { ObbInfo obbInfo; try { - obbInfo = mContainerService.getObbInfo(mObbState.ownerPath); + obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath); } catch (RemoteException e) { Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " - + mObbState.ownerPath); + + mObbState.canonicalPath); obbInfo = null; } if (obbInfo == null) { - throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath); + throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath); } return obbInfo; } @@ -3122,7 +3140,7 @@ class MountService extends IMountService.Stub int rc = StorageResultCode.OperationSucceeded; try { - mConnector.execute("obb", "mount", mObbState.voldPath, new SensitiveArg(hashedKey), + mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey), mObbState.ownerGid); } catch (NativeDaemonConnectorException e) { int code = e.getCode(); @@ -3133,7 +3151,7 @@ class MountService extends IMountService.Stub if (rc == StorageResultCode.OperationSucceeded) { if (DEBUG_OBB) - Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath); + Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath); synchronized (mObbMounts) { addObbStateLocked(mObbState); @@ -3194,7 +3212,7 @@ class MountService extends IMountService.Stub int rc = StorageResultCode.OperationSucceeded; try { - final Command cmd = new Command("obb", "unmount", mObbState.voldPath); + final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath); if (mForceUnmount) { cmd.appendArg("force"); } @@ -3240,49 +3258,6 @@ class MountService extends IMountService.Stub } } - @VisibleForTesting - public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) { - // TODO: allow caller to provide Environment for full testing - // TODO: extend to support OBB mounts on secondary external storage - - // Only adjust paths when storage is emulated - if (!Environment.isExternalStorageEmulated()) { - return canonicalPath; - } - - String path = canonicalPath.toString(); - - // First trim off any external storage prefix - final UserEnvironment userEnv = new UserEnvironment(userId); - - // /storage/emulated/0 - final String externalPath = userEnv.getExternalStorageDirectory().getAbsolutePath(); - // /storage/emulated_legacy - final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory() - .getAbsolutePath(); - - if (path.startsWith(externalPath)) { - path = path.substring(externalPath.length() + 1); - } else if (path.startsWith(legacyExternalPath)) { - path = path.substring(legacyExternalPath.length() + 1); - } else { - return canonicalPath; - } - - // Handle special OBB paths on emulated storage - final String obbPath = "Android/obb"; - if (path.startsWith(obbPath)) { - path = path.substring(obbPath.length() + 1); - - final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER); - return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path) - .getAbsolutePath(); - } - - // Handle normal external storage paths - return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath(); - } - private static class Callbacks extends Handler { private static final int MSG_STORAGE_STATE_CHANGED = 1; private static final int MSG_VOLUME_STATE_CHANGED = 2; diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 24b90d81996d..d4e798fc45b8 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -477,8 +477,8 @@ final class ActivityRecord { } } - boolean isNotResolverActivity() { - return !ResolverActivity.class.getName().equals(realActivity.getClassName()); + boolean isResolverActivity() { + return ResolverActivity.class.getName().equals(realActivity.getClassName()); } ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, @@ -605,7 +605,7 @@ final class ActivityRecord { _intent.getData() == null && _intent.getType() == null && (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && - isNotResolverActivity()) { + !isResolverActivity()) { // This sure looks like a home activity! mActivityType = HOME_ACTIVITY_TYPE; } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index a796ea7d4ab5..f549af8c0c53 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1153,7 +1153,7 @@ final class ActivityStack { next.results = null; next.newIntents = null; - if (next.isHomeActivity() && next.isNotResolverActivity()) { + if (next.isHomeActivity()) { ProcessRecord app = next.task.mActivities.get(0).app; if (app != null && app != mService.mHomeProcess) { mService.mHomeProcess = app; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 98b6ee6d2402..ac7b9b1400c2 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1262,7 +1262,7 @@ public final class ActivityStackSupervisor implements DisplayListener { r.userId, System.identityHashCode(r), task.taskId, r.shortComponentName); } - if (r.isHomeActivity() && r.isNotResolverActivity()) { + if (r.isHomeActivity()) { // Home process is the root process of the task. mService.mHomeProcess = task.mActivities.get(0).app; } @@ -2024,6 +2024,14 @@ public final class ActivityStackSupervisor implements DisplayListener { reuseTask = inTask; } else { inTask = null; + // Launch ResolverActivity in the source task, so that it stays in the task + // bounds when in freeform workspace. + // Also put noDisplay activities in the source task. These by itself can + // be placed in any task/stack, however it could launch other activities + // like ResolverActivity, and we want those to stay in the original task. + if (r.isResolverActivity() || r.noDisplay) { + addingToTask = true; + } } if (inTask == null) { @@ -3091,7 +3099,7 @@ public final class ActivityStackSupervisor implements DisplayListener { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId); final Configuration overrideConfig = task.updateOverrideConfiguration(bounds); - // This variable holds information whether the configuration didn't change in a signficant + // This variable holds information whether the configuration didn't change in a significant // way and the activity was kept the way it was. If it's false, it means the activity had // to be relaunched due to configuration change. boolean kept = true; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e49a7e49822c..c4b57f1945a1 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -501,7 +501,6 @@ public class AudioService extends IAudioService.Stub { private volatile IRingtonePlayer mRingtonePlayer; private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; - private int mDeviceRotation = Surface.ROTATION_0; // Request to override default use of A2DP for media. private boolean mBluetoothA2dpEnabled; @@ -545,8 +544,6 @@ public class AudioService extends IAudioService.Stub { // If absolute volume is supported in AVRCP device private boolean mAvrcpAbsVolSupported = false; - private AudioOrientationEventListener mOrientationListener; - private static Long mLastDeviceConnectMsgTime = new Long(0); private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate; @@ -669,15 +666,7 @@ public class AudioService extends IAudioService.Stub { } mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false); if (mMonitorRotation) { - mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)) - .getDefaultDisplay().getRotation(); - Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation); - - mOrientationListener = new AudioOrientationEventListener(mContext); - mOrientationListener.enable(); - - // initialize rotation in AudioSystem - setRotationForAudioSystem(); + RotationHelper.init(mContext, mAudioHandler); } context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null); @@ -805,7 +794,7 @@ public class AudioService extends IAudioService.Stub { setOrientationForAudioSystem(); } if (mMonitorRotation) { - setRotationForAudioSystem(); + RotationHelper.updateOrientation(); } synchronized (mBluetoothA2dpEnabledLock) { @@ -1058,25 +1047,6 @@ public class AudioService extends IAudioService.Stub { return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); } - private class AudioOrientationEventListener - extends OrientationEventListener { - public AudioOrientationEventListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(int orientation) { - //Even though we're responding to phone orientation events, - //use display rotation so audio stays in sync with video/dialogs - int newRotation = ((WindowManager) mContext.getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); - if (newRotation != mDeviceRotation) { - mDeviceRotation = newRotation; - setRotationForAudioSystem(); - } - } - } - /////////////////////////////////////////////////////////////////////////// // IPC methods /////////////////////////////////////////////////////////////////////////// @@ -5066,14 +5036,13 @@ public class AudioService extends IAudioService.Stub { } } else if (action.equals(Intent.ACTION_SCREEN_ON)) { if (mMonitorRotation) { - mOrientationListener.onOrientationChanged(0); //argument is ignored anyway - mOrientationListener.enable(); + RotationHelper.enable(); } AudioSystem.setParameters("screen_state=on"); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { if (mMonitorRotation) { //reduce wakeups (save current) by only listening when display is on - mOrientationListener.disable(); + RotationHelper.disable(); } AudioSystem.setParameters("screen_state=off"); } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { @@ -5322,6 +5291,7 @@ public class AudioService extends IAudioService.Stub { } } + //TODO move to an external "orientation helper" class private void setOrientationForAudioSystem() { switch (mDeviceOrientation) { case Configuration.ORIENTATION_LANDSCAPE: @@ -5345,26 +5315,6 @@ public class AudioService extends IAudioService.Stub { } } - private void setRotationForAudioSystem() { - switch (mDeviceRotation) { - case Surface.ROTATION_0: - AudioSystem.setParameters("rotation=0"); - break; - case Surface.ROTATION_90: - AudioSystem.setParameters("rotation=90"); - break; - case Surface.ROTATION_180: - AudioSystem.setParameters("rotation=180"); - break; - case Surface.ROTATION_270: - AudioSystem.setParameters("rotation=270"); - break; - default: - Log.e(TAG, "Unknown device rotation"); - } - } - - // Handles request to override default use of A2DP for media. // Must be called synchronized on mConnectedDevices public void setBluetoothA2dpOnInt(boolean on) { diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java new file mode 100644 index 000000000000..f03e6c7c545a --- /dev/null +++ b/services/core/java/com/android/server/audio/RotationHelper.java @@ -0,0 +1,209 @@ +/* + * 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.server.audio; + +import android.content.Context; +import android.media.AudioSystem; +import android.os.Handler; +import android.util.Log; +import android.view.OrientationEventListener; +import android.view.Surface; +import android.view.WindowManager; + +import com.android.server.policy.WindowOrientationListener; + +/** + * Class to handle device rotation events for AudioService, and forward device rotation + * to the audio HALs through AudioSystem. + * + * The role of this class is to monitor device orientation changes, and upon rotation, + * verify the UI orientation. In case of a change, send the new orientation, in increments + * of 90deg, through AudioSystem. + * + * Note that even though we're responding to device orientation events, we always + * query the display rotation so audio stays in sync with video/dialogs. This is + * done with .getDefaultDisplay().getRotation() from WINDOW_SERVICE. + */ +class RotationHelper { + + private static final String TAG = "AudioService.RotationHelper"; + + private static AudioOrientationListener sOrientationListener; + private static AudioWindowOrientationListener sWindowOrientationListener; + + private static final Object sRotationLock = new Object(); + private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock + + private static Context sContext; + + /** + * post conditions: + * - (sWindowOrientationListener != null) xor (sOrientationListener != null) + * - sWindowOrientationListener xor sOrientationListener is enabled + * - sContext != null + */ + static void init(Context context, Handler handler) { + if (context == null) { + throw new IllegalArgumentException("Invalid null context"); + } + sContext = context; + sWindowOrientationListener = new AudioWindowOrientationListener(context, handler); + sWindowOrientationListener.enable(); + if (!sWindowOrientationListener.canDetectOrientation()) { + // cannot use com.android.server.policy.WindowOrientationListener, revert to public + // orientation API + Log.i(TAG, "Not using WindowOrientationListener, reverting to OrientationListener"); + sWindowOrientationListener.disable(); + sWindowOrientationListener = null; + sOrientationListener = new AudioOrientationListener(context); + sOrientationListener.enable(); + } + } + + static void enable() { + if (sWindowOrientationListener != null) { + sWindowOrientationListener.enable(); + } else { + sOrientationListener.enable(); + } + updateOrientation(); + } + + static void disable() { + if (sWindowOrientationListener != null) { + sWindowOrientationListener.disable(); + } else { + sOrientationListener.disable(); + } + } + + /** + * Query current display rotation and publish the change if any. + */ + static void updateOrientation() { + // Even though we're responding to device orientation events, + // use display rotation so audio stays in sync with video/dialogs + int newRotation = ((WindowManager) sContext.getSystemService( + Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); + synchronized(sRotationLock) { + if (newRotation != sDeviceRotation) { + sDeviceRotation = newRotation; + publishRotation(sDeviceRotation); + } + } + } + + private static void publishRotation(int rotation) { + Log.v(TAG, "publishing device rotation =" + rotation + " (x90deg)"); + switch (rotation) { + case Surface.ROTATION_0: + AudioSystem.setParameters("rotation=0"); + break; + case Surface.ROTATION_90: + AudioSystem.setParameters("rotation=90"); + break; + case Surface.ROTATION_180: + AudioSystem.setParameters("rotation=180"); + break; + case Surface.ROTATION_270: + AudioSystem.setParameters("rotation=270"); + break; + default: + Log.e(TAG, "Unknown device rotation"); + } + } + + /** + * Uses android.view.OrientationEventListener + */ + final static class AudioOrientationListener extends OrientationEventListener { + AudioOrientationListener(Context context) { + super(context); + } + + @Override + public void onOrientationChanged(int orientation) { + updateOrientation(); + } + } + + /** + * Uses com.android.server.policy.WindowOrientationListener + */ + final static class AudioWindowOrientationListener extends WindowOrientationListener { + private static RotationCheckThread sRotationCheckThread; + + AudioWindowOrientationListener(Context context, Handler handler) { + super(context, handler); + } + + public void onProposedRotationChanged(int rotation) { + updateOrientation(); + if (sRotationCheckThread != null) { + sRotationCheckThread.endCheck(); + } + sRotationCheckThread = new RotationCheckThread(); + sRotationCheckThread.beginCheck(); + } + } + + /** + * When com.android.server.policy.WindowOrientationListener report an orientation change, + * the UI may not have rotated yet. This thread polls with gradually increasing delays + * the new orientation. + */ + final static class RotationCheckThread extends Thread { + // how long to wait between each rotation check + private final int[] WAIT_TIMES_MS = { 10, 20, 50, 100, 100, 200, 200, 500 }; + private int mWaitCounter; + private final Object mCounterLock = new Object(); + + RotationCheckThread() { + super("RotationCheck"); + } + + void beginCheck() { + synchronized(mCounterLock) { + mWaitCounter = 0; + } + try { + start(); + } catch (IllegalStateException e) { } + } + + void endCheck() { + synchronized(mCounterLock) { + mWaitCounter = WAIT_TIMES_MS.length; + } + } + + public void run() { + int newRotation; + while (mWaitCounter < WAIT_TIMES_MS.length) { + updateOrientation(); + int waitTimeMs; + synchronized(mCounterLock) { + waitTimeMs = WAIT_TIMES_MS[mWaitCounter]; + mWaitCounter++; + } + try { + sleep(waitTimeMs); + } catch (InterruptedException e) { } + } + } + } +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index a441cb2e511b..6e32e5c575f5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -946,7 +946,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE, - UserHandle.USER_OWNER); + UserHandle.USER_SYSTEM); final int gid = UserHandle.getSharedAppGid(uid); if (!PackageHelper.fixSdPermissions(cid, gid, null)) { throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2009ccf797ab..99562f3df59e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1108,7 +1108,7 @@ public class PackageManagerService extends IPackageManager.Stub { Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); if (mContext.bindServiceAsUser(service, mDefContainerConn, - Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { + Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mBound = true; return true; @@ -1715,7 +1715,7 @@ public class PackageManagerService extends IPackageManager.Stub { for (PackageSetting ps : packages) { Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten"); deletePackage(ps.name, new LegacyPackageDeleteObserver(null).getBinder(), - UserHandle.USER_OWNER, PackageManager.DELETE_ALL_USERS); + UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS); } mSettings.onVolumeForgotten(fsUuid); @@ -1726,7 +1726,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId, String[] grantedPermissions) { - if (userId >= UserHandle.USER_OWNER) { + if (userId >= UserHandle.USER_SYSTEM) { grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions); } else if (userId == UserHandle.USER_ALL) { final int[] userIds; @@ -2276,7 +2276,7 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.enableSystemPackageLPw(packageName); try { - scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null); + scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, UserHandle.SYSTEM); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse original system package: " + e.getMessage()); @@ -2401,8 +2401,9 @@ public class PackageManagerService extends IPackageManager.Stub { private String getRequiredVerifierLPr() { final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); + // We only care about verifier that's installed under system user. final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, - PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */); + PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM); String requiredVerifier = null; @@ -2417,7 +2418,7 @@ public class PackageManagerService extends IPackageManager.Stub { final String packageName = info.activityInfo.packageName; if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, - packageName, UserHandle.USER_OWNER) != PackageManager.PERMISSION_GRANTED) { + packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) { continue; } @@ -2437,7 +2438,7 @@ public class PackageManagerService extends IPackageManager.Stub { installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); final List<ResolveInfo> installers = queryIntentActivities(installerIntent, - PACKAGE_MIME_TYPE, 0, 0); + PACKAGE_MIME_TYPE, 0, UserHandle.USER_SYSTEM); String requiredInstaller = null; @@ -2467,7 +2468,7 @@ public class PackageManagerService extends IPackageManager.Stub { private ComponentName getIntentFilterVerifierComponentNameLPr() { final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, - PackageManager.GET_DISABLED_COMPONENTS, 0 /* userId */); + PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM); ComponentName verifierComponentName = null; @@ -2488,7 +2489,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT, - packageName, UserHandle.USER_OWNER) != PackageManager.PERMISSION_GRANTED) { + packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) { continue; } @@ -2784,8 +2785,7 @@ public class PackageManagerService extends IPackageManager.Stub { if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { return -1; } - p = ps.pkg; - return p != null ? UserHandle.getUid(userId, p.applicationInfo.uid) : -1; + return UserHandle.getUid(userId, ps.pkg.applicationInfo.uid); } } @@ -5690,7 +5690,7 @@ public class PackageManagerService extends IPackageManager.Stub { } try { scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK, - scanFlags, currentTime, null); + scanFlags, currentTime, UserHandle.SYSTEM); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage()); @@ -5796,6 +5796,8 @@ public class PackageManagerService extends IPackageManager.Stub { */ private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { + Preconditions.checkNotNull(user); + if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(); @@ -5837,7 +5839,7 @@ public class PackageManagerService extends IPackageManager.Stub { } boolean updatedPkgBetter = false; // First check if this is a system package that may involve an update - if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { + if (updatedPkg != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) { // If new package is not located in "/system/priv-app" (e.g. due to an OTA), // it needs to drop FLAG_PRIVILEGED. if (locationIsPrivileged(scanFile)) { @@ -6932,7 +6934,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { // This is a normal package, need to make its data directory. dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid, - UserHandle.USER_OWNER, pkg.packageName); + UserHandle.USER_SYSTEM, pkg.packageName); boolean uidError = false; if (dataPath.exists()) { @@ -7090,7 +7092,7 @@ public class PackageManagerService extends IPackageManager.Stub { // if they already exist if (!TextUtils.isEmpty(pkg.volumeUuid)) { for (int userId : userIds) { - if (userId != 0) { + if (userId != UserHandle.USER_SYSTEM) { mInstaller.createUserData(pkg.volumeUuid, pkg.packageName, UserHandle.getUid(userId, pkg.applicationInfo.uid), userId, pkg.applicationInfo.seinfo); @@ -7218,7 +7220,6 @@ public class PackageManagerService extends IPackageManager.Stub { for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) { if (name.equals(sysPs.pkg.libraryNames.get(j))) { allowed = true; - allowed = true; break; } } @@ -9603,7 +9604,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (am != null) { try { am.startService(null, intent, null, mContext.getOpPackageName(), - UserHandle.USER_OWNER); + UserHandle.USER_SYSTEM); } catch (RemoteException e) { } } @@ -10322,7 +10323,8 @@ public class PackageManagerService extends IPackageManager.Stub { + " to BM for possible restore"); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token); try { - if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) { + // TODO: http://b/22388012 + if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) { bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token); } else { doRestore = false; @@ -10803,14 +10805,11 @@ public class PackageManagerService extends IPackageManager.Stub { mArgs = args; if (ret == PackageManager.INSTALL_SUCCEEDED) { - /* - * ADB installs appear as UserHandle.USER_ALL, and can only be performed by - * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER. - */ - int userIdentifier = getUser().getIdentifier(); - if (userIdentifier == UserHandle.USER_ALL - && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) { - userIdentifier = UserHandle.USER_OWNER; + // TODO: http://b/22976637 + // Apps installed for "all" users use the device owner to verify the app + UserHandle verifierUser = getUser(); + if (verifierUser == UserHandle.ALL) { + verifierUser = UserHandle.SYSTEM; } /* @@ -10818,9 +10817,9 @@ public class PackageManagerService extends IPackageManager.Stub { * do, then we'll defer to them to verify the packages. */ final int requiredUid = mRequiredVerifierPackage == null ? -1 - : getPackageUid(mRequiredVerifierPackage, userIdentifier); + : getPackageUid(mRequiredVerifierPackage, verifierUser.getIdentifier()); if (!origin.existing && requiredUid != -1 - && isVerificationEnabled(userIdentifier, installFlags)) { + && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) { final Intent verification = new Intent( Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); @@ -10830,7 +10829,7 @@ public class PackageManagerService extends IPackageManager.Stub { final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS, - 0 /* TODO: Which userId? */); + verifierUser.getIdentifier()); if (DEBUG_VERIFY) { Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent " @@ -10885,12 +10884,6 @@ public class PackageManagerService extends IPackageManager.Stub { final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, receivers, verificationState); - // Apps installed for "all" users use the device owner to verify the app - UserHandle verifierUser = getUser(); - if (verifierUser == UserHandle.ALL) { - verifierUser = UserHandle.OWNER; - } - /* * If any sufficient verifiers were listed in the package * manifest, attempt to ask them. @@ -12121,7 +12114,8 @@ public class PackageManagerService extends IPackageManager.Stub { (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME; try { - scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null); + scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, + UserHandle.SYSTEM); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: " + e.getMessage()); @@ -12616,7 +12610,7 @@ public class PackageManagerService extends IPackageManager.Stub { final int verifierUid = getPackageUid( mIntentFilterVerifierComponent.getPackageName(), - (userId == UserHandle.USER_ALL) ? UserHandle.USER_OWNER : userId); + (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS); final Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); @@ -12816,11 +12810,14 @@ public class PackageManagerService extends IPackageManager.Stub { Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(observer); final int uid = Binder.getCallingUid(); - if (UserHandle.getUserId(uid) != userId) { + final boolean deleteAllUsers = (flags & PackageManager.DELETE_ALL_USERS) != 0; + final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId }; + if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) { mContext.enforceCallingPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "deletePackage for user " + userId); } + if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) { try { observer.onPackageDeleted(packageName, @@ -12830,25 +12827,15 @@ public class PackageManagerService extends IPackageManager.Stub { return; } - boolean uninstallBlocked = false; - if ((flags & PackageManager.DELETE_ALL_USERS) != 0) { - int[] users = sUserManager.getUserIds(); - for (int i = 0; i < users.length; ++i) { - if (getBlockUninstallForUser(packageName, users[i])) { - uninstallBlocked = true; - break; + for (int currentUserId : users) { + if (getBlockUninstallForUser(packageName, currentUserId)) { + try { + observer.onPackageDeleted(packageName, + PackageManager.DELETE_FAILED_OWNER_BLOCKED, null); + } catch (RemoteException re) { } + return; } - } else { - uninstallBlocked = getBlockUninstallForUser(packageName, userId); - } - if (uninstallBlocked) { - try { - observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED, - null); - } catch (RemoteException re) { - } - return; } if (DEBUG_REMOVE) { @@ -12859,13 +12846,11 @@ public class PackageManagerService extends IPackageManager.Stub { public void run() { mHandler.removeCallbacks(this); final int returnCode = deletePackageX(packageName, userId, flags); - if (observer != null) { - try { - observer.onPackageDeleted(packageName, returnCode, null); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } //end catch - } //end if + try { + observer.onPackageDeleted(packageName, returnCode, null); + } catch (RemoteException e) { + Log.i(TAG, "Observer no longer exists."); + } //end catch } //end run }); } @@ -13063,7 +13048,7 @@ public class PackageManagerService extends IPackageManager.Stub { final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs, userId); if (userIdToKill == UserHandle.USER_ALL - || userIdToKill >= UserHandle.USER_OWNER) { + || userIdToKill >= UserHandle.USER_SYSTEM) { // If gids changed for this user, kill all affected packages. mHandler.post(new Runnable() { @Override @@ -13180,7 +13165,8 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageParser.Package newPkg; try { - newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null); + newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, + UserHandle.SYSTEM); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage()); return false; @@ -13431,7 +13417,7 @@ public class PackageManagerService extends IPackageManager.Stub { } final ClearStorageConnection conn = new ClearStorageConnection(); if (mContext.bindServiceAsUser( - containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { + containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) { try { for (int curUser : users) { long timeout = SystemClock.uptimeMillis() + 5000; @@ -15743,7 +15729,8 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { PackageParser.Package pkg = null; try { - pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0, null); + pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0, + UserHandle.SYSTEM); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage()); } @@ -15903,7 +15890,8 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { final PackageParser.Package pkg; try { - pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0L, null); + pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, + UserHandle.SYSTEM); loaded.add(pkg.applicationInfo); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 6386a916d518..31fc24bef4f9 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -131,6 +131,8 @@ public class UserManagerService extends IUserManager.Stub { private static final String XML_SUFFIX = ".xml"; private static final int MIN_USER_ID = 10; + // We need to keep process uid within Integer.MAX_VALUE. + private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE; private static final int USER_VERSION = 6; @@ -844,7 +846,7 @@ public class UserManagerService extends IUserManager.Stub { int userVersion = mUserVersion; if (userVersion < 1) { // Assign a proper name for the owner, if not initialized correctly before - UserInfo user = mUsers.get(UserHandle.USER_OWNER); + UserInfo user = mUsers.get(UserHandle.USER_SYSTEM); if ("Primary".equals(user.name)) { user.name = mContext.getResources().getString(com.android.internal.R.string.owner_name); scheduleWriteUserLocked(user); @@ -854,7 +856,7 @@ public class UserManagerService extends IUserManager.Stub { if (userVersion < 2) { // Owner should be marked as initialized - UserInfo user = mUsers.get(UserHandle.USER_OWNER); + UserInfo user = mUsers.get(UserHandle.USER_SYSTEM); if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) { user.flags |= UserInfo.FLAG_INITIALIZED; scheduleWriteUserLocked(user); @@ -1518,6 +1520,11 @@ public class UserManagerService extends IUserManager.Stub { long ident = Binder.clearCallingIdentity(); try { final UserInfo user; + int currentUser = ActivityManager.getCurrentUser(); + if (currentUser == userHandle) { + Log.w(LOG_TAG, "Current user cannot be removed"); + return false; + } synchronized (mPackagesLock) { user = mUsers.get(userHandle); if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) { @@ -2005,14 +2012,14 @@ public class UserManagerService extends IUserManager.Stub { private int getNextAvailableIdLocked() { synchronized (mPackagesLock) { int i = MIN_USER_ID; - while (i < Integer.MAX_VALUE) { + while (i < MAX_USER_ID) { if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) { - break; + return i; } i++; } - return i; } + throw new IllegalStateException("No user id available!"); } private String packageToRestrictionsFileName(String packageName) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c265000f13f5..4f30a1531701 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -778,6 +778,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private final Runnable mUpdateRotationRunnable = new Runnable() { @Override public void run() { + // send interaction hint to improve redraw performance + mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION, 0); updateRotation(false); } }; diff --git a/services/core/java/com/android/server/wm/DimBehindController.java b/services/core/java/com/android/server/wm/DimBehindController.java new file mode 100644 index 000000000000..c56af39f6c93 --- /dev/null +++ b/services/core/java/com/android/server/wm/DimBehindController.java @@ -0,0 +1,291 @@ +package com.android.server.wm; + +import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER; + +import android.graphics.Rect; +import android.util.ArrayMap; +import android.util.Slog; +import android.util.TypedValue; + +import java.io.PrintWriter; + +/** + * Centralizes the control of dim layers used for + * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}. + */ +class DimBehindController { + private static final String TAG = "DimBehindController"; + + /** Amount of time in milliseconds to animate the dim surface from one value to another, + * when no window animation is driving it. */ + private static final int DEFAULT_DIM_DURATION = 200; + + // Shared dim layer for fullscreen users. {@link DimBehindState#dimLayer} will point to this + // instead of creating a new object per fullscreen task on a display. + private DimLayer mSharedFullScreenDimLayer; + + private ArrayMap<DimLayer.DimLayerUser, DimBehindState> mState = new ArrayMap<>(); + + private DisplayContent mDisplayContent; + + private Rect mTmpBounds = new Rect(); + + DimBehindController(DisplayContent displayContent) { + mDisplayContent = displayContent; + } + + /** Updates the dim layer bounds, recreating it if needed. */ + void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) { + DimBehindState state = getOrCreateDimBehindState(dimLayerUser); + final boolean previousFullscreen = state.dimLayer != null + && state.dimLayer == mSharedFullScreenDimLayer; + DimLayer newDimLayer; + final int displayId = mDisplayContent.getDisplayId(); + if (dimLayerUser.isFullscreen()) { + if (previousFullscreen) { + // Nothing to do here... + return; + } + // Use shared fullscreen dim layer + newDimLayer = mSharedFullScreenDimLayer; + if (newDimLayer == null) { + if (state.dimLayer != null) { + // Re-purpose the previous dim layer. + newDimLayer = state.dimLayer; + } else { + // Create new full screen dim layer. + newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId); + } + dimLayerUser.getBounds(mTmpBounds); + newDimLayer.setBounds(mTmpBounds); + mSharedFullScreenDimLayer = newDimLayer; + } else if (state.dimLayer != null) { + state.dimLayer. destroySurface(); + } + } else { + newDimLayer = (state.dimLayer == null || previousFullscreen) + ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId) + : state.dimLayer; + dimLayerUser.getBounds(mTmpBounds); + newDimLayer.setBounds(mTmpBounds); + } + state.dimLayer = newDimLayer; + } + + private DimBehindState getOrCreateDimBehindState(DimLayer.DimLayerUser dimLayerUser) { + if (DEBUG_DIM_LAYER) Slog.v(TAG, "getDimBehindState, dimLayerUser=" + + dimLayerUser.toShortString()); + DimBehindState state = mState.get(dimLayerUser); + if (state == null) { + state = new DimBehindState(); + mState.put(dimLayerUser, state); + } + return state; + } + + private void setContinueDimming(DimLayer.DimLayerUser dimLayerUser) { + DimBehindState state = mState.get(dimLayerUser); + if (state == null) { + if (DEBUG_DIM_LAYER) Slog.w(TAG, "setContinueDimming, no state for: " + + dimLayerUser.toShortString()); + return; + } + state.continueDimming = true; + } + + boolean isDimming() { + for (int i = mState.size() - 1; i >= 0; i--) { + DimBehindState state = mState.valueAt(i); + if (state.dimLayer != null && state.dimLayer.isDimming()) { + return true; + } + } + return false; + } + + void resetDimming() { + for (int i = mState.size() - 1; i >= 0; i--) { + mState.valueAt(i).continueDimming = false; + } + } + + private boolean getContinueDimming(DimLayer.DimLayerUser dimLayerUser) { + DimBehindState state = mState.get(dimLayerUser); + return state != null && state.continueDimming; + } + + void startDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser, + WindowStateAnimator newWinAnimator) { + // Only set dim params on the highest dimmed layer. + // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. + DimBehindState state = getOrCreateDimBehindState(dimLayerUser); + if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded," + + " dimLayerUser=" + dimLayerUser.toShortString() + + " newWinAnimator=" + newWinAnimator + + " state.animator=" + state.animator); + if (newWinAnimator.mSurfaceShown && (state.animator == null + || !state.animator.mSurfaceShown + || state.animator.mAnimLayer <= newWinAnimator.mAnimLayer)) { + state.animator = newWinAnimator; + if (state.animator.mWin.mAppToken == null && !dimLayerUser.isFullscreen()) { + // Dim should cover the entire screen for system windows. + mDisplayContent.getLogicalDisplayRect(mTmpBounds); + state.dimLayer.setBounds(mTmpBounds); + } + } + } + + void stopDimmingIfNeeded() { + if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded, mState.size()=" + mState.size()); + for (int i = mState.size() - 1; i >= 0; i--) { + DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i); + stopDimmingIfNeeded(dimLayerUser); + } + } + + private void stopDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser) { + // No need to check if state is null, we know the key has a value. + DimBehindState state = mState.get(dimLayerUser); + if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded," + + " dimLayerUser=" + dimLayerUser.toShortString() + + " state.continueDimming=" + state.continueDimming + + " state.dimLayer.isDimming=" + state.dimLayer.isDimming()); + if (!state.continueDimming && state.dimLayer.isDimming()) { + state.animator = null; + dimLayerUser.getBounds(mTmpBounds); + state.dimLayer.setBounds(mTmpBounds); + } + } + + boolean animateDimLayers() { + int fullScreen = -1; + for (int i = mState.size() - 1; i >= 0; i--) { + DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i); + if (dimLayerUser.isFullscreen()) { + fullScreen = i; + if (mState.valueAt(i).continueDimming) { + break; + } + } + } + if (fullScreen != -1) { + return animateDimLayers(mState.keyAt(fullScreen)); + } else { + boolean result = false; + for (int i = mState.size() - 1; i >= 0; i--) { + result |= animateDimLayers(mState.keyAt(i)); + } + return result; + } + } + + private boolean animateDimLayers(DimLayer.DimLayerUser dimLayerUser) { + DimBehindState state = mState.get(dimLayerUser); + if (DEBUG_DIM_LAYER) Slog.v(TAG, "animateDimLayers," + + " dimLayerUser=" + dimLayerUser.toShortString() + + " state.animator=" + state.animator + + " state.continueDimming=" + state.continueDimming); + final int dimLayer; + final float dimAmount; + if (state.animator == null) { + dimLayer = state.dimLayer.getLayer(); + dimAmount = 0; + } else { + dimLayer = state.animator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; + dimAmount = state.animator.mWin.mAttrs.dimAmount; + } + final float targetAlpha = state.dimLayer.getTargetAlpha(); + if (targetAlpha != dimAmount) { + if (state.animator == null) { + state.dimLayer.hide(DEFAULT_DIM_DURATION); + } else { + long duration = (state.animator.mAnimating && state.animator.mAnimation != null) + ? state.animator.mAnimation.computeDurationHint() + : DEFAULT_DIM_DURATION; + if (targetAlpha > dimAmount) { + duration = getDimBehindFadeDuration(duration); + } + state.dimLayer.show(dimLayer, dimAmount, duration); + } + } else if (state.dimLayer.getLayer() != dimLayer) { + state.dimLayer.setLayer(dimLayer); + } + if (state.dimLayer.isAnimating()) { + if (!mDisplayContent.mService.okToDisplay()) { + // Jump to the end of the animation. + state.dimLayer.show(); + } else { + return state.dimLayer.stepAnimation(); + } + } + return false; + } + + boolean isDimming(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator winAnimator) { + DimBehindState state = mState.get(dimLayerUser); + return state != null && state.animator == winAnimator && state.dimLayer.isDimming(); + } + + private long getDimBehindFadeDuration(long duration) { + TypedValue tv = new TypedValue(); + mDisplayContent.mService.mContext.getResources().getValue( + com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); + if (tv.type == TypedValue.TYPE_FRACTION) { + duration = (long) tv.getFraction(duration, duration); + } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { + duration = tv.data; + } + return duration; + } + + void close() { + for (int i = mState.size() - 1; i >= 0; i--) { + DimBehindState state = mState.valueAt(i); + state.dimLayer.destroySurface(); + } + mState.clear(); + mSharedFullScreenDimLayer = null; + } + + void removeDimLayerUser(DimLayer.DimLayerUser dimLayerUser) { + mState.remove(dimLayerUser); + } + + void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) { + if (dimLayerUser == null) { + Slog.e(TAG, "Trying to apply dim layer for: " + this + + ", but no dim layer user found."); + return; + } + if (!getContinueDimming(dimLayerUser)) { + setContinueDimming(dimLayerUser); + if (!isDimming(dimLayerUser, animator)) { + if (DEBUG_DIM_LAYER) Slog.v(TAG, "Win " + this + " start dimming."); + startDimmingIfNeeded(dimLayerUser, animator); + } + } + } + + private static class DimBehindState { + // The particular window with FLAG_DIM_BEHIND set. If null, hide dimLayer. + WindowStateAnimator animator; + // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the + // end then stop any dimming. + boolean continueDimming; + DimLayer dimLayer; + } + + void dump(String prefix, PrintWriter pw) { + pw.println(prefix + "DimBehindController"); + for (int i = 0, n = mState.size(); i < n; i++) { + pw.println(prefix + " " + mState.keyAt(i).toShortString()); + pw.print(prefix + " "); + DimBehindState state = mState.valueAt(i); + pw.print("dimLayer=" + (state.dimLayer == mSharedFullScreenDimLayer ? "shared" : + state.dimLayer)); + pw.print(", animator=" + state.animator); + pw.println(", continueDimming=" + state.continueDimming + "}"); + + } + } +} diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java index 538d6b846d46..8c479d8ef6aa 100644 --- a/services/core/java/com/android/server/wm/DimLayer.java +++ b/services/core/java/com/android/server/wm/DimLayer.java @@ -65,6 +65,9 @@ public class DimLayer { boolean isFullscreen(); /** Returns the display info. of the dim layer user. */ DisplayInfo getDisplayInfo(); + /** Gets the bounds of the dim layer user. */ + void getBounds(Rect outBounds); + String toShortString(); } /** The user of this dim layer. */ final DimLayerUser mUser; @@ -239,8 +242,9 @@ public class DimLayer { mDuration = duration; } } - if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime); mTargetAlpha = alpha; + if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime + + " mTargetAlpha=" + mTargetAlpha); } /** Immediate hide. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 6b5ecdc70a7b..f13f350cc9d4 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -115,6 +115,8 @@ class DisplayContent { final DockedStackDividerController mDividerControllerLocked; + final DimBehindController mDimBehindController; + /** * @param display May not be null. * @param service You know. @@ -128,6 +130,7 @@ class DisplayContent { mService = service; initializeDisplayBaseInfo(); mDividerControllerLocked = new DockedStackDividerController(service.mContext, this); + mDimBehindController = new DimBehindController(this); } int getDisplayId() { @@ -246,6 +249,7 @@ class DisplayContent { } void detachStack(TaskStack stack) { + mDimBehindController.removeDimLayerUser(stack); mStacks.remove(stack); } @@ -382,54 +386,23 @@ class DisplayContent { } boolean animateDimLayers() { - boolean result = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - final Task task = tasks.get(taskNdx); - result |= task.animateDimLayers(); - if (task.isFullscreen()) { - // No point in continuing as this task covers the entire screen. - // Also, fullscreen tasks all share the same dim layer, so we don't want - // processing of fullscreen task below this one affecting the dim layer state. - return result; - } - } - } - return result; + return mDimBehindController.animateDimLayers(); } void resetDimming() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - tasks.get(taskNdx).clearContinueDimming(); - } - } + mDimBehindController.resetDimming(); } boolean isDimming() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - if (tasks.get(taskNdx).isDimming()) { - return true; - } - } - } - return false; + return mDimBehindController.isDimming(); } void stopDimmingIfNeeded() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - tasks.get(taskNdx).stopDimmingIfNeeded(); - } - } + mDimBehindController.stopDimmingIfNeeded(); } void close() { + mDimBehindController.close(); for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { mStacks.get(stackNdx).close(); } @@ -576,6 +549,7 @@ class DisplayContent { } } pw.println(); + mDimBehindController.dump(prefix + " ", pw); } @Override diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 8c5d319439ba..b9028e39a1c1 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.ActivityManager.DOCKED_STACK_ID; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; @@ -25,16 +26,15 @@ import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static com.android.server.wm.TaskStack.DOCKED_BOTTOM; -import static com.android.server.wm.TaskStack.DOCKED_INVALID; import static com.android.server.wm.TaskStack.DOCKED_LEFT; import static com.android.server.wm.TaskStack.DOCKED_RIGHT; import static com.android.server.wm.TaskStack.DOCKED_TOP; import android.content.Context; +import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.RemoteException; -import android.util.Slog; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -58,7 +58,6 @@ public class DockedStackDividerController implements View.OnTouchListener { private Rect mOriginalRect = new Rect(); private int mDockSide; - DockedStackDividerController(Context context, DisplayContent displayContent) { mContext = context; mDisplayContent = displayContent; @@ -66,13 +65,16 @@ public class DockedStackDividerController implements View.OnTouchListener { com.android.internal.R.dimen.docked_stack_divider_thickness); } - private void addDivider() { + private void addDivider(Configuration configuration) { View view = LayoutInflater.from(mContext).inflate( com.android.internal.R.layout.docked_stack_divider, null); view.setOnTouchListener(this); WindowManagerGlobal manager = WindowManagerGlobal.getInstance(); + final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE; + final int width = landscape ? mDividerWidth : MATCH_PARENT; + final int height = landscape ? MATCH_PARENT : mDividerWidth; WindowManager.LayoutParams params = new WindowManager.LayoutParams( - mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER, + width, height, TYPE_DOCK_DIVIDER, FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH, PixelFormat.OPAQUE); @@ -92,10 +94,13 @@ public class DockedStackDividerController implements View.OnTouchListener { return mView != null; } - void update() { + void update(Configuration configuration, boolean forceUpdate) { + if (forceUpdate && mView != null) { + removeDivider(); + } TaskStack stack = mDisplayContent.getDockedStackLocked(); if (stack != null && mView == null) { - addDivider(); + addDivider(configuration); } else if (stack == null && mView != null) { removeDivider(); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 1f986dd90b10..c4600e02dfb9 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -29,7 +29,6 @@ import android.graphics.Rect; import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; -import android.util.TypedValue; import android.view.DisplayInfo; import android.view.Surface; @@ -39,10 +38,6 @@ import java.io.PrintWriter; import java.util.ArrayList; class Task implements DimLayer.DimLayerUser { - /** Amount of time in milliseconds to animate the dim surface from one value to another, - * when no window animation is driving it. */ - private static final int DEFAULT_DIM_DURATION = 200; - // Return value from {@link setBounds} indicating no change was made to the Task bounds. static final int BOUNDS_CHANGE_NONE = 0; // Return value from {@link setBounds} indicating the position of the Task bounds changed. @@ -78,17 +73,6 @@ class Task implements DimLayer.DimLayerUser { // Whether the task is currently being drag-resized private boolean mDragResizing; - // The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. - WindowStateAnimator mDimWinAnimator; - // Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} - private DimLayer mDimLayer; - // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end - // then stop any dimming. - private boolean mContinueDimming; - // Shared dim layer for fullscreen tasks. {@link #mDimLayer} will point to this instead - // of creating a new object per fullscreen task on a display. - private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>(); - Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration config) { mTaskId = taskId; @@ -128,6 +112,10 @@ class Task implements DimLayer.DimLayerUser { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask"); mDeferRemoval = false; + DisplayContent content = getDisplayContent(); + if (content != null) { + content.mDimBehindController.removeDimLayerUser(this); + } mStack.removeTask(this); mService.mTaskIdToTask.delete(mTaskId); } @@ -228,7 +216,9 @@ class Task implements DimLayer.DimLayerUser { mBounds.set(bounds); mRotation = rotation; - updateDimLayer(); + if (displayContent != null) { + displayContent.mDimBehindController.updateDimLayer(this); + } mOverrideConfig = mFullscreen ? Configuration.EMPTY : config; return boundsChange; } @@ -261,7 +251,8 @@ class Task implements DimLayer.DimLayerUser { } /** Bounds of the task with other system factors taken into consideration. */ - void getBounds(Rect out) { + @Override + public void getBounds(Rect out) { if (useCurrentBounds()) { // No need to adjust the output bounds if fullscreen or the docked stack is visible // since it is already what we want to represent to the rest of the system. @@ -303,142 +294,12 @@ class Task implements DimLayer.DimLayerUser { if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) { // Post message to inform activity manager of the bounds change simulating // a one-way call. We do this to prevent a deadlock between window manager - // lock and activity manager lock been held. - mService.mH.sendMessage(mService.mH.obtainMessage( - RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds)); - } - } - - /** Updates the dim layer bounds, recreating it if needed. */ - private void updateDimLayer() { - DimLayer newDimLayer; - final boolean previousFullscreen = - mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1; - final int displayId = mStack.getDisplayContent().getDisplayId(); - if (mFullscreen) { - if (previousFullscreen) { - // Nothing to do here... - return; + // lock and activity manager lock been held. Only tasks within the freeform stack + // are resizeable independently of their stack resizing. + if (mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { + mService.mH.sendMessage(mService.mH.obtainMessage( + RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds)); } - // Use shared fullscreen dim layer - newDimLayer = sSharedFullscreenDimLayers.get(displayId); - if (newDimLayer == null) { - if (mDimLayer != null) { - // Re-purpose the previous dim layer. - newDimLayer = mDimLayer; - } else { - // Create new full screen dim layer. - newDimLayer = new DimLayer(mService, this, displayId); - } - newDimLayer.setBounds(mBounds); - sSharedFullscreenDimLayers.put(displayId, newDimLayer); - } else if (mDimLayer != null) { - mDimLayer.destroySurface(); - } - } else { - newDimLayer = (mDimLayer == null || previousFullscreen) - ? new DimLayer(mService, this, displayId) : mDimLayer; - newDimLayer.setBounds(mBounds); - } - mDimLayer = newDimLayer; - } - - boolean animateDimLayers() { - final int dimLayer; - final float dimAmount; - if (mDimWinAnimator == null) { - dimLayer = mDimLayer.getLayer(); - dimAmount = 0; - } else { - dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; - dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount; - } - final float targetAlpha = mDimLayer.getTargetAlpha(); - if (targetAlpha != dimAmount) { - if (mDimWinAnimator == null) { - mDimLayer.hide(DEFAULT_DIM_DURATION); - } else { - long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null) - ? mDimWinAnimator.mAnimation.computeDurationHint() - : DEFAULT_DIM_DURATION; - if (targetAlpha > dimAmount) { - duration = getDimBehindFadeDuration(duration); - } - mDimLayer.show(dimLayer, dimAmount, duration); - } - } else if (mDimLayer.getLayer() != dimLayer) { - mDimLayer.setLayer(dimLayer); - } - if (mDimLayer.isAnimating()) { - if (!mService.okToDisplay()) { - // Jump to the end of the animation. - mDimLayer.show(); - } else { - return mDimLayer.stepAnimation(); - } - } - return false; - } - - private long getDimBehindFadeDuration(long duration) { - TypedValue tv = new TypedValue(); - mService.mContext.getResources().getValue( - com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); - if (tv.type == TypedValue.TYPE_FRACTION) { - duration = (long)tv.getFraction(duration, duration); - } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { - duration = tv.data; - } - return duration; - } - - void clearContinueDimming() { - mContinueDimming = false; - } - - void setContinueDimming() { - mContinueDimming = true; - } - - boolean getContinueDimming() { - return mContinueDimming; - } - - boolean isDimming() { - return mDimLayer.isDimming(); - } - - boolean isDimming(WindowStateAnimator winAnimator) { - return mDimWinAnimator == winAnimator && isDimming(); - } - - void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) { - // Only set dim params on the highest dimmed layer. - // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. - if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null - || !mDimWinAnimator.mSurfaceShown - || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) { - mDimWinAnimator = newWinAnimator; - if (mDimWinAnimator.mWin.mAppToken == null - && !mFullscreen && mStack.getDisplayContent() != null) { - // Dim should cover the entire screen for system windows. - mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect); - mDimLayer.setBounds(mTmpRect); - } - } - } - - void stopDimmingIfNeeded() { - if (!mContinueDimming && isDimming()) { - mDimWinAnimator = null; - mDimLayer.setBounds(mBounds); - } - } - - void close() { - if (mDimLayer != null) { - mDimLayer.destroySurface(); - mDimLayer = null; } } @@ -491,16 +352,14 @@ class Task implements DimLayer.DimLayerUser { return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}"; } + @Override + public String toShortString() { + return "Task=" + mTaskId; + } + public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("taskId="); pw.print(mTaskId); pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens); pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval); - if (mDimLayer.isDimming()) { - pw.print(prefix); pw.println("mDimLayer:"); - mDimLayer.printTo(prefix + " ", pw); - pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); - } else { - pw.println(); - } } } diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 9da7406e8d3c..207da47773f8 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -146,13 +146,18 @@ class TaskPositioner implements DimLayer.DimLayerUser { } synchronized (mService.mWindowMap) { mDragEnded = notifyMoveLocked(newX, newY); + mTask.getBounds(mTmpRect); + } + if (!mTmpRect.equals(mWindowDragBounds)) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, + "wm.TaskPositioner.resizeTask"); + try { + mService.mActivityManager.resizeTask( + mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); + } catch (RemoteException e) { + } + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask"); - try { - mService.mActivityManager.resizeTask( - mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); - } catch(RemoteException e) {} - Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } break; case MotionEvent.ACTION_UP: { @@ -171,11 +176,12 @@ class TaskPositioner implements DimLayer.DimLayerUser { } if (mDragEnded) { + final boolean wasResizing = mResizing; synchronized (mService.mWindowMap) { endDragLocked(); } try { - if (mResizing) { + if (wasResizing) { // We were using fullscreen surface during resizing. Request // resizeTask() one last time to restore surface to window size. mService.mActivityManager.resizeTask( @@ -462,6 +468,16 @@ class TaskPositioner implements DimLayer.DimLayerUser { return mTask.mStack.getDisplayInfo(); } + @Override + public void getBounds(Rect out) { + // This dim layer user doesn't need this. + } + + @Override + public String toShortString() { + return TAG; + } + private int getDragLayerLocked() { return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG) * WindowManagerService.TYPE_LAYER_MULTIPLIER diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index f030b9a23e64..a63099301571 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -175,6 +175,10 @@ public class TaskStack implements DimLayer.DimLayerUser { return false; } + if (mDisplayContent != null) { + mDisplayContent.mDimBehindController.updateDimLayer(this); + } + mAnimationBackgroundSurface.setBounds(bounds); mBounds.set(bounds); mRotation = rotation; @@ -201,7 +205,8 @@ public class TaskStack implements DimLayer.DimLayerUser { } /** Bounds of the stack with other system factors taken into consideration. */ - void getBounds(Rect out) { + @Override + public void getBounds(Rect out) { if (useCurrentBounds()) { // No need to adjust the output bounds if fullscreen or the docked stack is visible // since it is already what we want to represent to the rest of the system. @@ -550,9 +555,6 @@ public class TaskStack implements DimLayer.DimLayerUser { mAnimationBackgroundSurface.destroySurface(); mAnimationBackgroundSurface = null; } - for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { - mTasks.get(taskNdx).close(); - } mDisplayContent = null; } @@ -609,6 +611,11 @@ public class TaskStack implements DimLayer.DimLayerUser { return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; } + @Override + public String toShortString() { + return "Stack=" + mStackId; + } + /** * For docked workspace provides information which side of the screen was the dock anchored. */ diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 74572cfcdee2..1b72876dcb14 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -216,6 +216,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_STACK = false; static final boolean DEBUG_DISPLAY = false; static final boolean DEBUG_POWER = false; + static final boolean DEBUG_DIM_LAYER = false; static final boolean SHOW_SURFACE_ALLOC = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; @@ -3419,12 +3420,20 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { + final boolean orientationChanged = mCurConfiguration.orientation != config.orientation; mCurConfiguration = new Configuration(config); if (mWaitingForConfig) { mWaitingForConfig = false; mLastFinishedFreezeSource = "new-config"; } mWindowPlacerLocked.performSurfacePlacement(); + if (orientationChanged) { + for (int i = mDisplayContents.size() - 1; i >= 0; i--) { + DisplayContent content = mDisplayContents.valueAt(i); + Message.obtain(mH, H.UPDATE_DOCKED_STACK_DIVIDER, H.DOCK_DIVIDER_FORCE_UPDATE, + H.UNUSED, content).sendToTarget(); + } + } } } @@ -7164,6 +7173,21 @@ public class WindowManagerService extends IWindowManager.Stub public static final int RESIZE_STACK = 43; public static final int RESIZE_TASK = 44; + /** + * Used to indicate in the message that the dock divider needs to be updated only if it's + * necessary. + */ + static final int DOCK_DIVIDER_NO_FORCE_UPDATE = 0; + /** + * Used to indicate in the message that the dock divider should be force-removed before + * updating, so new configuration can be applied. + */ + static final int DOCK_DIVIDER_FORCE_UPDATE = 1; + /** + * Used to denote that an integer field in a message will not be used. + */ + public static final int UNUSED = 0; + @Override public void handleMessage(Message msg) { if (DEBUG_WINDOW_TRACE) { @@ -7705,8 +7729,9 @@ public class WindowManagerService extends IWindowManager.Stub break; case UPDATE_DOCKED_STACK_DIVIDER: { DisplayContent content = (DisplayContent) msg.obj; + final boolean forceUpdate = msg.arg1 == DOCK_DIVIDER_FORCE_UPDATE; synchronized (mWindowMap) { - content.mDividerControllerLocked.update(); + content.mDividerControllerLocked.update(mCurConfiguration, forceUpdate); } } break; @@ -8356,8 +8381,10 @@ public class WindowManagerService extends IWindowManager.Stub layerChanged = true; anyLayerChanged = true; } - final Task task = w.getTask(); - if (layerChanged && task != null && task.isDimming(winAnimator)) { + final DimLayer.DimLayerUser dimLayerUser = w.getDimLayerUser(); + final DisplayContent displayContent = w.getDisplayContent(); + if (layerChanged && dimLayerUser != null && displayContent != null && + displayContent.mDimBehindController.isDimming(dimLayerUser, winAnimator)) { // Force an animation pass just to update the mDimLayer layer. scheduleAnimationLocked(); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 55ddbc06d959..8ace99053cf4 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -29,6 +29,7 @@ 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.WindowManagerService.DEBUG_CONFIGURATION; +import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER; import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerService.DEBUG_POWER; @@ -698,10 +699,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { final int height = Math.min(mFrame.height(), mContentFrame.height()); final int width = Math.min(mContentFrame.width(), mFrame.width()); final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); - final int minVisibleHeight = - mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics); - final int minVisibleWidth = - mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics); + final int minVisibleHeight = WindowManagerService.dipToPixel( + MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics); + final int minVisibleWidth = WindowManagerService.dipToPixel( + MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics); final int top = Math.max(mContentFrame.top, Math.min(mFrame.top, mContentFrame.bottom - minVisibleHeight)); final int left = Math.max(mContentFrame.left + minVisibleWidth - width, @@ -889,7 +890,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { @Override public boolean isVoiceInteraction() { - return mAppToken != null ? mAppToken.voiceInteraction : false; + return mAppToken != null && mAppToken.voiceInteraction; } boolean setInsetsChanged() { @@ -934,7 +935,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { return task.mStack; } } - return null; + // Some system windows (e.g. "Power off" dialog) don't have a task, but we would still + // associate them with some stack to enable dimming. + return mAttrs.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW + && mDisplayContent != null ? mDisplayContent.getHomeStack() : null; } /** @@ -970,7 +974,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { } if (forTouch && inFreeformWorkspace()) { final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); - final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics); + final int delta = WindowManagerService.dipToPixel( + RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics); bounds.inset(-delta, -delta); } } @@ -1031,8 +1036,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { return false; } final AppWindowToken atoken = mAppToken; - final boolean animating = atoken != null - ? (atoken.mAppAnimator.animation != null) : false; + final boolean animating = atoken != null && atoken.mAppAnimator.animation != null; return mHasSurface && !mDestroying && !mExiting && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested) && ((!mAttachedHidden && mViewVisibility == View.VISIBLE @@ -1114,8 +1118,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { * of a transition that has not yet been started. */ boolean isReadyForDisplay() { - if (mRootToken.waitingToShow && - mService.mAppTransition.isTransitionSet()) { + if (mRootToken.waitingToShow && mService.mAppTransition.isTransitionSet()) { return false; } return mHasSurface && mPolicyVisibility && !mDestroying @@ -1295,19 +1298,20 @@ final class WindowState implements WindowManagerPolicy.WindowState { } void handleFlagDimBehind() { - if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isDisplayedLw() && !mExiting) { - final Task task = getTask(); - if (task == null) { - return; - } - task.setContinueDimming(); - if (!task.isDimming(mWinAnimator)) { - if (WindowManagerService.localLOGV) Slog.v(TAG, "Win " + this + " start dimming."); - task.startDimmingIfNeeded(mWinAnimator); - } + if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && mDisplayContent != null && !mExiting + && isDisplayedLw()) { + mDisplayContent.mDimBehindController.applyDimBehind(getDimLayerUser(), mWinAnimator); } } + DimLayer.DimLayerUser getDimLayerUser() { + Task task = getTask(); + if (task != null) { + return task; + } + return getStack(); + } + void maybeRemoveReplacedWindow() { AppWindowToken token = mAppToken; if (token != null && token.mReplacingWindow) { @@ -1512,11 +1516,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { @Override public boolean isDimming() { - Task task = getTask(); - if (task == null) { - return false; - } - return task.isDimming(mWinAnimator); + final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser(); + return dimLayerUser != null && mDisplayContent != null && + mDisplayContent.mDimBehindController.isDimming(dimLayerUser, mWinAnimator); } public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 60bf57154bc6..ed53501ff443 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1516,12 +1516,7 @@ class WindowStateAnimator { mDsDy * w.mHScale, mDtDy * w.mVScale); mAnimator.setPendingLayoutChanges(w.getDisplayId(), WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER); - if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) { - final Task task = w.getTask(); - if (task != null) { - task.startDimmingIfNeeded(this); - } - } + w.handleFlagDimBehind(); } catch (RuntimeException e) { // If something goes wrong with the surface (such // as running out of memory), don't take down the diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index df0a1c9d43d5..112646ad7818 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -642,9 +642,7 @@ class WindowSurfacePlacer { handleNotObscuredLocked(w, innerDw, innerDh); } - if (task != null && !task.getContinueDimming()) { - w.handleFlagDimBehind(); - } + w.handleFlagDimBehind(); if (isDefaultDisplay && obscuredChanged && mWallpaperControllerLocked.isWallpaperTarget(w) && w.isVisibleLw()) { @@ -967,7 +965,8 @@ class WindowSurfacePlacer { } mService.mPolicy.finishLayoutLw(); - mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget(); + mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER, + DOCK_DIVIDER_NO_FORCE_UPDATE, UNUSED, displayContent).sendToTarget(); } /** diff --git a/services/tests/servicestests/src/com/android/server/MountServiceTests.java b/services/tests/servicestests/src/com/android/server/MountServiceTests.java index 9c88b406ccf3..ecfe0db103fe 100644 --- a/services/tests/servicestests/src/com/android/server/MountServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/MountServiceTests.java @@ -27,8 +27,6 @@ import android.test.ComparisonFailure; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; -import static com.android.server.MountService.buildObbPath; - import com.android.frameworks.servicestests.R; import java.io.File; @@ -42,16 +40,6 @@ public class MountServiceTests extends AndroidTestCase { private static final String OBB_MOUNT_PREFIX = "/mnt/obb/"; - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - private static void assertStartsWith(String message, String prefix, String actual) { if (!actual.startsWith(prefix)) { throw new ComparisonFailure(message, prefix, actual); @@ -195,8 +183,7 @@ public class MountServiceTests extends AndroidTestCase { final ObbObserver observer = new ObbObserver(); assertTrue("unmountObb call on test1.obb should succeed", - sm.unmountObb(file.getPath(), - false, observer)); + sm.unmountObb(file.getPath(), false, observer)); assertTrue("Unmount should have completed", observer.waitForCompletion()); @@ -284,34 +271,4 @@ public class MountServiceTests extends AndroidTestCase { unmountObb(sm, file1, OnObbStateChangeListener.UNMOUNTED); unmountObb(sm, file2, OnObbStateChangeListener.UNMOUNTED); } - - public void testBuildObbPath() { - final int userId = 10; - - // Paths outside external storage should remain untouched - assertEquals("/storage/random/foo", - buildObbPath("/storage/random/foo", userId, true)); - assertEquals("/storage/random/foo", - buildObbPath("/storage/random/foo", userId, false)); - - // Paths on user-specific emulated storage - assertEquals("/mnt/shell/emulated/10/foo", - buildObbPath("/storage/emulated_legacy/foo", userId, true)); - assertEquals("/storage/emulated/10/foo", - buildObbPath("/storage/emulated_legacy/foo", userId, false)); - assertEquals("/mnt/shell/emulated/10/foo", - buildObbPath("/storage/emulated/10/foo", userId, true)); - assertEquals("/storage/emulated/10/foo", - buildObbPath("/storage/emulated/10/foo", userId, false)); - - // Paths on shared OBB emulated storage - assertEquals("/mnt/shell/emulated/obb/foo", - buildObbPath("/storage/emulated_legacy/Android/obb/foo", userId, true)); - assertEquals("/storage/emulated/0/Android/obb/foo", - buildObbPath("/storage/emulated_legacy/Android/obb/foo", userId, false)); - assertEquals("/mnt/shell/emulated/obb/foo", - buildObbPath("/storage/emulated/10/Android/obb/foo", userId, true)); - assertEquals("/storage/emulated/0/Android/obb/foo", - buildObbPath("/storage/emulated/10/Android/obb/foo", userId, false)); - } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 7f813ec59313..3160e3961495 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -753,7 +753,7 @@ public class UsbDeviceManager { UsbManager.USB_FUNCTION_MTP) || UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP); - if (active && mCurrentUser != UserHandle.USER_NULL) { + if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) { Slog.v(TAG, "Current user switched to " + mCurrentUser + "; resetting USB host stack for MTP or PTP"); setEnabledFunctions(mCurrentFunctions, true); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java index b458d9b14096..7628c5c24941 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java @@ -188,7 +188,7 @@ public class MultiProducerActivity extends Activity implements OnClickListener { // This call should be done while the rendernode's displaylist is produced. // For simplicity of this test we do this before we kick off the draw. mContent.getLocationInSurface(surfaceOrigin); - mRenderer.setContentOverdrawProtectionBounds(surfaceOrigin[0], surfaceOrigin[1], + mRenderer.setContentDrawBounds(surfaceOrigin[0], surfaceOrigin[1], surfaceOrigin[0] + mContent.getWidth(), surfaceOrigin[1] + mContent.getHeight()); // Determine new position for frame. |