summaryrefslogtreecommitdiff
path: root/android/view
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-11-17 16:38:15 -0500
committerJustin Klaassen <justinklaassen@google.com>2017-11-17 16:38:15 -0500
commit6a65f2da209bff03cb0eb6da309710ac6ee5026d (patch)
tree48e2090e716d4178378cb0599fc5d9cffbcf3f63 /android/view
parent46c77c203439b3b37c99d09e326df4b1fe08c10b (diff)
downloadandroid-28-6a65f2da209bff03cb0eb6da309710ac6ee5026d.tar.gz
Import Android SDK Platform P [4456821]
/google/data/ro/projects/android/fetch_artifact \ --bid 4456821 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4456821.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: I2d206b200d7952f899a5d1647ab532638cc8dd43
Diffstat (limited to 'android/view')
-rw-r--r--android/view/Display.java29
-rw-r--r--android/view/DisplayFrames.java189
-rw-r--r--android/view/FocusFinder.java2
-rw-r--r--android/view/IWindowManagerImpl.java6
-rw-r--r--android/view/NotificationHeaderView.java14
-rw-r--r--android/view/RenderNode.java7
-rw-r--r--android/view/RenderNodeAnimator.java10
-rw-r--r--android/view/SurfaceControl.java34
-rw-r--r--android/view/ThreadedRenderer.java7
-rw-r--r--android/view/View.java22
-rw-r--r--android/view/ViewConfiguration.java2
-rw-r--r--android/view/ViewRootImpl.java2
-rw-r--r--android/view/WindowManager.java17
-rw-r--r--android/view/WindowManagerGlobal.java3
-rw-r--r--android/view/WindowManagerInternal.java33
-rw-r--r--android/view/WindowManagerPolicy.java65
-rw-r--r--android/view/accessibility/AccessibilityInteractionClient.java91
-rw-r--r--android/view/accessibility/AccessibilityManager.java7
-rw-r--r--android/view/autofill/AutofillManager.java52
-rw-r--r--android/view/textclassifier/TextClassification.java28
-rw-r--r--android/view/textclassifier/TextClassifier.java84
-rw-r--r--android/view/textclassifier/TextClassifierImpl.java275
-rw-r--r--android/view/textclassifier/TextLinks.java252
-rw-r--r--android/view/textclassifier/TextSelection.java53
-rw-r--r--android/view/textclassifier/logging/SmartSelectionEventTracker.java179
25 files changed, 1001 insertions, 462 deletions
diff --git a/android/view/Display.java b/android/view/Display.java
index e7c3f92d..6a44cdb9 100644
--- a/android/view/Display.java
+++ b/android/view/Display.java
@@ -294,11 +294,10 @@ public final class Display {
/**
* Display state: The display is dozing in a suspended low power state; it is still
- * on but is optimized for showing static system-provided content while the device
- * is non-interactive. This mode may be used to conserve even more power by allowing
- * the hardware to stop applying frame buffer updates from the graphics subsystem or
- * to take over the display and manage it autonomously to implement low power always-on
- * display functionality.
+ * on but the CPU is not updating it. This may be used in one of two ways: to show
+ * static system-provided content while the device is non-interactive, or to allow
+ * a "Sidekick" compute resource to update the display. For this reason, the
+ * CPU must not control the display in this mode.
*
* @see #getState
* @see android.os.PowerManager#isInteractive
@@ -313,6 +312,18 @@ public final class Display {
*/
public static final int STATE_VR = 5;
+ /**
+ * Display state: The display is in a suspended full power state; it is still
+ * on but the CPU is not updating it. This may be used in one of two ways: to show
+ * static system-provided content while the device is non-interactive, or to allow
+ * a "Sidekick" compute resource to update the display. For this reason, the
+ * CPU must not control the display in this mode.
+ *
+ * @see #getState
+ * @see android.os.PowerManager#isInteractive
+ */
+ public static final int STATE_ON_SUSPEND = 6;
+
/* The color mode constants defined below must be kept in sync with the ones in
* system/core/include/system/graphics-base.h */
@@ -994,7 +1005,7 @@ public final class Display {
* Gets the state of the display, such as whether it is on or off.
*
* @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
- * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, or
+ * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, {@link #STATE_ON_SUSPEND}, or
* {@link #STATE_UNKNOWN}.
*/
public int getState() {
@@ -1113,6 +1124,8 @@ public final class Display {
return "DOZE_SUSPEND";
case STATE_VR:
return "VR";
+ case STATE_ON_SUSPEND:
+ return "ON_SUSPEND";
default:
return Integer.toString(state);
}
@@ -1120,11 +1133,11 @@ public final class Display {
/**
* Returns true if display updates may be suspended while in the specified
- * display power state.
+ * display power state. In SUSPEND states, updates are absolutely forbidden.
* @hide
*/
public static boolean isSuspendedState(int state) {
- return state == STATE_OFF || state == STATE_DOZE_SUSPEND;
+ return state == STATE_OFF || state == STATE_DOZE_SUSPEND || state == STATE_ON_SUSPEND;
}
/**
diff --git a/android/view/DisplayFrames.java b/android/view/DisplayFrames.java
new file mode 100644
index 00000000..e6861d83
--- /dev/null
+++ b/android/view/DisplayFrames.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.view;
+
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
+
+import android.graphics.Rect;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+
+/**
+ * Container class for all the display frames that affect how we do window layout on a display.
+ * @hide
+ */
+public class DisplayFrames {
+ public final int mDisplayId;
+
+ /**
+ * The current size of the screen; really; extends into the overscan area of the screen and
+ * doesn't account for any system elements like the status bar.
+ */
+ public final Rect mOverscan = new Rect();
+
+ /**
+ * The current visible size of the screen; really; (ir)regardless of whether the status bar can
+ * be hidden but not extending into the overscan area.
+ */
+ public final Rect mUnrestricted = new Rect();
+
+ /** Like mOverscan*, but allowed to move into the overscan region where appropriate. */
+ public final Rect mRestrictedOverscan = new Rect();
+
+ /**
+ * The current size of the screen; these may be different than (0,0)-(dw,dh) if the status bar
+ * can't be hidden; in that case it effectively carves out that area of the display from all
+ * other windows.
+ */
+ public final Rect mRestricted = new Rect();
+
+ /**
+ * During layout, the current screen borders accounting for any currently visible system UI
+ * elements.
+ */
+ public final Rect mSystem = new Rect();
+
+ /** For applications requesting stable content insets, these are them. */
+ public final Rect mStable = new Rect();
+
+ /**
+ * For applications requesting stable content insets but have also set the fullscreen window
+ * flag, these are the stable dimensions without the status bar.
+ */
+ public final Rect mStableFullscreen = new Rect();
+
+ /**
+ * During layout, the current screen borders with all outer decoration (status bar, input method
+ * dock) accounted for.
+ */
+ public final Rect mCurrent = new Rect();
+
+ /**
+ * During layout, the frame in which content should be displayed to the user, accounting for all
+ * screen decoration except for any space they deem as available for other content. This is
+ * usually the same as mCurrent*, but may be larger if the screen decor has supplied content
+ * insets.
+ */
+ public final Rect mContent = new Rect();
+
+ /**
+ * During layout, the frame in which voice content should be displayed to the user, accounting
+ * for all screen decoration except for any space they deem as available for other content.
+ */
+ public final Rect mVoiceContent = new Rect();
+
+ /** During layout, the current screen borders along which input method windows are placed. */
+ public final Rect mDock = new Rect();
+
+ private final Rect mDisplayInfoOverscan = new Rect();
+ private final Rect mRotatedDisplayInfoOverscan = new Rect();
+ public int mDisplayWidth;
+ public int mDisplayHeight;
+
+ public int mRotation;
+
+ public DisplayFrames(int displayId, DisplayInfo info) {
+ mDisplayId = displayId;
+ onDisplayInfoUpdated(info);
+ }
+
+ public void onDisplayInfoUpdated(DisplayInfo info) {
+ mDisplayWidth = info.logicalWidth;
+ mDisplayHeight = info.logicalHeight;
+ mRotation = info.rotation;
+ mDisplayInfoOverscan.set(
+ info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
+ }
+
+ public void onBeginLayout() {
+ switch (mRotation) {
+ case ROTATION_90:
+ mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
+ mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.right;
+ mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.bottom;
+ mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.left;
+ break;
+ case ROTATION_180:
+ mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.right;
+ mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.bottom;
+ mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.left;
+ mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.top;
+ break;
+ case ROTATION_270:
+ mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.bottom;
+ mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.left;
+ mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.top;
+ mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.right;
+ break;
+ default:
+ mRotatedDisplayInfoOverscan.set(mDisplayInfoOverscan);
+ break;
+ }
+
+ mRestrictedOverscan.set(0, 0, mDisplayWidth, mDisplayHeight);
+ mOverscan.set(mRestrictedOverscan);
+ mSystem.set(mRestrictedOverscan);
+ mUnrestricted.set(mRotatedDisplayInfoOverscan);
+ mUnrestricted.right = mDisplayWidth - mUnrestricted.right;
+ mUnrestricted.bottom = mDisplayHeight - mUnrestricted.bottom;
+ mRestricted.set(mUnrestricted);
+ mDock.set(mUnrestricted);
+ mContent.set(mUnrestricted);
+ mVoiceContent.set(mUnrestricted);
+ mStable.set(mUnrestricted);
+ mStableFullscreen.set(mUnrestricted);
+ mCurrent.set(mUnrestricted);
+
+ }
+
+ public int getInputMethodWindowVisibleHeight() {
+ return mDock.bottom - mCurrent.bottom;
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ mStable.writeToProto(proto, STABLE_BOUNDS);
+ proto.end(token);
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
+ + " r=" + mRotation);
+ final String myPrefix = prefix + " ";
+ dumpFrame(mStable, "mStable", myPrefix, pw);
+ dumpFrame(mStableFullscreen, "mStableFullscreen", myPrefix, pw);
+ dumpFrame(mDock, "mDock", myPrefix, pw);
+ dumpFrame(mCurrent, "mCurrent", myPrefix, pw);
+ dumpFrame(mSystem, "mSystem", myPrefix, pw);
+ dumpFrame(mContent, "mContent", myPrefix, pw);
+ dumpFrame(mVoiceContent, "mVoiceContent", myPrefix, pw);
+ dumpFrame(mOverscan, "mOverscan", myPrefix, pw);
+ dumpFrame(mRestrictedOverscan, "mRestrictedOverscan", myPrefix, pw);
+ dumpFrame(mRestricted, "mRestricted", myPrefix, pw);
+ dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
+ dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
+ dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
+ }
+
+ private void dumpFrame(Rect frame, String name, String prefix, PrintWriter pw) {
+ pw.print(prefix + name + "="); frame.printShortString(pw); pw.println();
+ }
+}
diff --git a/android/view/FocusFinder.java b/android/view/FocusFinder.java
index 74555de5..713cfb48 100644
--- a/android/view/FocusFinder.java
+++ b/android/view/FocusFinder.java
@@ -530,7 +530,7 @@ public class FocusFinder {
* axis distances. Warning: this fudge factor is finely tuned, be sure to
* run all focus tests if you dare tweak it.
*/
- int getWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance) {
+ long getWeightedDistanceFor(long majorAxisDistance, long minorAxisDistance) {
return 13 * majorAxisDistance * majorAxisDistance
+ minorAxisDistance * minorAxisDistance;
}
diff --git a/android/view/IWindowManagerImpl.java b/android/view/IWindowManagerImpl.java
index b34dfbfe..6c006cae 100644
--- a/android/view/IWindowManagerImpl.java
+++ b/android/view/IWindowManagerImpl.java
@@ -16,6 +16,7 @@
package android.view;
+import android.app.IAssistDataReceiver;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
@@ -29,7 +30,6 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.DisplayMetrics;
-import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -261,7 +261,7 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver)
+ public boolean requestAssistScreenshot(IAssistDataReceiver receiver)
throws RemoteException {
// TODO Auto-generated method stub
return false;
@@ -507,7 +507,7 @@ public class IWindowManagerImpl implements IWindowManager {
throws RemoteException {}
@Override
- public void createInputConsumer(String name, InputChannel inputChannel)
+ public void createInputConsumer(IBinder token, String name, InputChannel inputChannel)
throws RemoteException {}
@Override
diff --git a/android/view/NotificationHeaderView.java b/android/view/NotificationHeaderView.java
index 58045602..ab0b3eec 100644
--- a/android/view/NotificationHeaderView.java
+++ b/android/view/NotificationHeaderView.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -43,6 +44,7 @@ public class NotificationHeaderView extends ViewGroup {
public static final int NO_COLOR = Notification.COLOR_INVALID;
private final int mChildMinWidth;
private final int mContentEndMargin;
+ private final int mGravity;
private View mAppName;
private View mHeaderText;
private OnClickListener mExpandClickListener;
@@ -50,7 +52,6 @@ public class NotificationHeaderView extends ViewGroup {
private ImageView mExpandButton;
private CachingIconView mIcon;
private View mProfileBadge;
- private View mInfo;
private int mIconColor;
private int mOriginalNotificationColor;
private boolean mExpanded;
@@ -61,6 +62,7 @@ public class NotificationHeaderView extends ViewGroup {
private boolean mEntireHeaderClickable;
private boolean mExpandOnlyOnButton;
private boolean mAcceptAllTouches;
+ private int mTotalWidth;
ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
@@ -92,6 +94,11 @@ public class NotificationHeaderView extends ViewGroup {
mHeaderBackgroundHeight = res.getDimensionPixelSize(
R.dimen.notification_header_background_height);
mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand);
+
+ int[] attrIds = { android.R.attr.gravity };
+ TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+ mGravity = ta.getInt(0, 0);
+ ta.recycle();
}
@Override
@@ -146,6 +153,7 @@ public class NotificationHeaderView extends ViewGroup {
mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
}
}
+ mTotalWidth = Math.min(totalWidth, givenWidth);
setMeasuredDimension(givenWidth, givenHeight);
}
@@ -153,6 +161,10 @@ public class NotificationHeaderView extends ViewGroup {
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = getPaddingStart();
int end = getMeasuredWidth();
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
+ if (centerAligned) {
+ left += getMeasuredWidth() / 2 - mTotalWidth / 2;
+ }
int childCount = getChildCount();
int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
for (int i = 0; i < childCount; i++) {
diff --git a/android/view/RenderNode.java b/android/view/RenderNode.java
index ea6e63c3..50701518 100644
--- a/android/view/RenderNode.java
+++ b/android/view/RenderNode.java
@@ -353,6 +353,11 @@ public class RenderNode {
return nHasShadow(mNativeRenderNode);
}
+ /** setShadowColor */
+ public boolean setShadowColor(int color) {
+ return nSetShadowColor(mNativeRenderNode, color);
+ }
+
/**
* Enables or disables clipping to the outline.
*
@@ -910,6 +915,8 @@ public class RenderNode {
@CriticalNative
private static native boolean nHasShadow(long renderNode);
@CriticalNative
+ private static native boolean nSetShadowColor(long renderNode, int color);
+ @CriticalNative
private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
@CriticalNative
private static native boolean nSetRevealClip(long renderNode,
diff --git a/android/view/RenderNodeAnimator.java b/android/view/RenderNodeAnimator.java
index 95150409..c4a71601 100644
--- a/android/view/RenderNodeAnimator.java
+++ b/android/view/RenderNodeAnimator.java
@@ -19,7 +19,6 @@ package android.view;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.util.SparseIntArray;
@@ -281,12 +280,9 @@ public class RenderNodeAnimator extends Animator {
setTarget(mViewTarget.mRenderNode);
}
- public void setTarget(Canvas canvas) {
- if (!(canvas instanceof DisplayListCanvas)) {
- throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
- }
- final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
- setTarget(recordingCanvas.mNode);
+ /** Sets the animation target to the owning view of the DisplayListCanvas */
+ public void setTarget(DisplayListCanvas canvas) {
+ setTarget(canvas.mNode);
}
private void setTarget(RenderNode node) {
diff --git a/android/view/SurfaceControl.java b/android/view/SurfaceControl.java
index 6f8315ae..5641009c 100644
--- a/android/view/SurfaceControl.java
+++ b/android/view/SurfaceControl.java
@@ -295,6 +295,12 @@ public class SurfaceControl {
public static final int POWER_MODE_DOZE_SUSPEND = 3;
/**
+ * Display power mode on: used while putting the screen into a suspended
+ * full power mode. Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ */
+ public static final int POWER_MODE_ON_SUSPEND = 4;
+
+ /**
* A value for windowType used to indicate that the window should be omitted from screenshots
* and display mirroring. A temporary workaround until we express such things with
* the hierarchy.
@@ -1206,56 +1212,65 @@ public class SurfaceControl {
}
public Transaction show(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
return this;
}
public Transaction hide(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
return this;
}
public Transaction setPosition(SurfaceControl sc, float x, float y) {
+ sc.checkNotReleased();
nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
return this;
}
public Transaction setSize(SurfaceControl sc, int w, int h) {
- nativeSetSize(mNativeObject, sc.mNativeObject,
- w, h);
+ sc.checkNotReleased();
+ nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
public Transaction setLayer(SurfaceControl sc, int z) {
+ sc.checkNotReleased();
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
+ sc.checkNotReleased();
nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
relativeTo.getHandle(), z);
return this;
}
public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
+ sc.checkNotReleased();
nativeSetTransparentRegionHint(mNativeObject,
sc.mNativeObject, transparentRegion);
return this;
}
public Transaction setAlpha(SurfaceControl sc, float alpha) {
+ sc.checkNotReleased();
nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
return this;
}
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
+ sc.checkNotReleased();
nativeSetMatrix(mNativeObject, sc.mNativeObject,
dsdx, dtdx, dtdy, dsdy);
return this;
}
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1267,6 +1282,7 @@ public class SurfaceControl {
}
public Transaction setFinalCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetFinalCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1278,40 +1294,48 @@ public class SurfaceControl {
}
public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+ sc.checkNotReleased();
nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
return this;
}
- public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) {
+ public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
+ long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber);
return this;
}
public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
barrierSurface.mNativeObject, frameNumber);
return this;
}
public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
return this;
}
/** Re-parents a specific child layer to a new parent */
public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparent(mNativeObject, sc.mNativeObject,
newParentHandle);
return this;
}
public Transaction detachChildren(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSeverChildren(mNativeObject, sc.mNativeObject);
return this;
}
public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
+ sc.checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
overrideScalingMode);
return this;
@@ -1322,6 +1346,7 @@ public class SurfaceControl {
* @param color A float array with three values to represent r, g, b in range [0..1]
*/
public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
+ sc.checkNotReleased();
nativeSetColor(mNativeObject, sc.mNativeObject, color);
return this;
}
@@ -1334,6 +1359,7 @@ public class SurfaceControl {
* (at which point the geometry influencing aspects of this transaction will then occur)
*/
public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetGeometryAppliesWithResize(mNativeObject, sc.mNativeObject);
return this;
}
@@ -1343,6 +1369,7 @@ public class SurfaceControl {
* Surface with the {@link #SECURE} flag.
*/
Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+ sc.checkNotReleased();
if (isSecure) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
} else {
@@ -1356,6 +1383,7 @@ public class SurfaceControl {
* Surface with the {@link #OPAQUE} flag.
*/
public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+ sc.checkNotReleased();
if (isOpaque) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
} else {
diff --git a/android/view/ThreadedRenderer.java b/android/view/ThreadedRenderer.java
index 2166f6e4..7c76bab2 100644
--- a/android/view/ThreadedRenderer.java
+++ b/android/view/ThreadedRenderer.java
@@ -70,6 +70,7 @@ public final class ThreadedRenderer {
* Name of the file that holds the shaders cache.
*/
private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
+ private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
/**
* System property used to enable or disable threaded rendering profiling.
@@ -272,7 +273,9 @@ public final class ThreadedRenderer {
* @hide
*/
public static void setupDiskCache(File cacheDir) {
- ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
+ ThreadedRenderer.setupShadersDiskCache(
+ new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
+ new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
}
/**
@@ -1007,7 +1010,7 @@ public final class ThreadedRenderer {
/** Not actually public - internal use only. This doc to make lint happy */
public static native void disableVsync();
- static native void setupShadersDiskCache(String cacheFile);
+ static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
private static native void nRotateProcessStatsBuffer();
private static native void nSetProcessStatsBuffer(int fd);
diff --git a/android/view/View.java b/android/view/View.java
index c043dcac..be09fe86 100644
--- a/android/view/View.java
+++ b/android/view/View.java
@@ -14218,6 +14218,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setScaleX(float scaleX) {
if (scaleX != getScaleX()) {
+ requireIsFinite(scaleX, "scaleX");
invalidateViewProperty(true, false);
mRenderNode.setScaleX(scaleX);
invalidateViewProperty(false, true);
@@ -14254,6 +14255,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setScaleY(float scaleY) {
if (scaleY != getScaleY()) {
+ requireIsFinite(scaleY, "scaleY");
invalidateViewProperty(true, false);
mRenderNode.setScaleY(scaleY);
invalidateViewProperty(false, true);
@@ -14803,6 +14805,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ private static void requireIsFinite(float transform, String propertyName) {
+ if (Float.isNaN(transform)) {
+ throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN");
+ }
+ if (Float.isInfinite(transform)) {
+ throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity");
+ }
+ }
+
/**
* The visual x position of this view, in pixels. This is equivalent to the
* {@link #setTranslationX(float) translationX} property plus the current
@@ -14889,6 +14900,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setElevation(float elevation) {
if (elevation != getElevation()) {
+ requireIsFinite(elevation, "elevation");
invalidateViewProperty(true, false);
mRenderNode.setElevation(elevation);
invalidateViewProperty(false, true);
@@ -14981,6 +14993,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setTranslationZ(float translationZ) {
if (translationZ != getTranslationZ()) {
+ requireIsFinite(translationZ, "translationZ");
invalidateViewProperty(true, false);
mRenderNode.setTranslationZ(translationZ);
invalidateViewProperty(false, true);
@@ -15169,6 +15182,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return mRenderNode.hasShadow();
}
+ /**
+ * @hide
+ */
+ public void setShadowColor(@ColorInt int color) {
+ if (mRenderNode.setShadowColor(color)) {
+ invalidateViewProperty(true, true);
+ }
+ }
+
/** @hide */
public void setRevealClip(boolean shouldClip, float x, float y, float radius) {
diff --git a/android/view/ViewConfiguration.java b/android/view/ViewConfiguration.java
index 45008627..c44c8dda 100644
--- a/android/view/ViewConfiguration.java
+++ b/android/view/ViewConfiguration.java
@@ -92,7 +92,7 @@ public class ViewConfiguration {
* Defines the duration in milliseconds a user needs to hold down the
* appropriate button to enable the accessibility shortcut once it's configured.
*/
- private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1500;
+ private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1000;
/**
* Defines the duration in milliseconds we will wait to see if a touch event
diff --git a/android/view/ViewRootImpl.java b/android/view/ViewRootImpl.java
index 37829f0b..e30496fb 100644
--- a/android/view/ViewRootImpl.java
+++ b/android/view/ViewRootImpl.java
@@ -513,7 +513,7 @@ public final class ViewRootImpl implements ViewParent,
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (!sCompatibilityDone) {
- sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
+ sAlwaysAssignFocus = true;
sCompatibilityDone = true;
}
diff --git a/android/view/WindowManager.java b/android/view/WindowManager.java
index c29a1daf..eb5fc92e 100644
--- a/android/view/WindowManager.java
+++ b/android/view/WindowManager.java
@@ -1422,7 +1422,7 @@ public interface WindowManager extends ViewManager {
* this window is visible.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+ @RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
/**
@@ -1443,6 +1443,15 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN = 0x00200000;
/**
+ * Flag to indicate that this window should be considered a screen decoration similar to the
+ * nav bar and status bar. This will cause this window to affect the window insets reported
+ * to other windows when it is visible.
+ * @hide
+ */
+ @RequiresPermission(permission.STATUS_BAR_SERVICE)
+ public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1526,7 +1535,11 @@ public interface WindowManager extends ViewManager {
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN,
equals = PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN,
- name = "ACQUIRES_SLEEP_TOKEN")
+ name = "ACQUIRES_SLEEP_TOKEN"),
+ @ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
+ equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
+ name = "IS_SCREEN_DECOR")
})
@TestApi
public int privateFlags;
diff --git a/android/view/WindowManagerGlobal.java b/android/view/WindowManagerGlobal.java
index c7e8dee3..cca66d6b 100644
--- a/android/view/WindowManagerGlobal.java
+++ b/android/view/WindowManagerGlobal.java
@@ -605,9 +605,10 @@ public final class WindowManagerGlobal {
public void setStoppedState(IBinder token, boolean stopped) {
synchronized (mLock) {
int count = mViews.size();
- for (int i = 0; i < count; i++) {
+ for (int i = count - 1; i >= 0; i--) {
if (token == null || mParams.get(i).token == token) {
ViewRootImpl root = mRoots.get(i);
+ // Client might remove the view by "stopped" event.
root.setWindowStopped(stopped);
}
}
diff --git a/android/view/WindowManagerInternal.java b/android/view/WindowManagerInternal.java
index 69cc1002..cd1b1908 100644
--- a/android/view/WindowManagerInternal.java
+++ b/android/view/WindowManagerInternal.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ClipData;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
@@ -140,6 +141,30 @@ public abstract class WindowManagerInternal {
}
/**
+ * An interface to customize drag and drop behaviors.
+ */
+ public interface IDragDropCallback {
+ /**
+ * Called when drag operation is started.
+ */
+ default boolean performDrag(IWindow window, IBinder dragToken,
+ int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data) {
+ return true;
+ }
+
+ /**
+ * Called when drop result is reported.
+ */
+ default void reportDropResult(IWindow window, boolean consumed) {}
+
+ /**
+ * Called when drag operation is cancelled.
+ */
+ default void cancelDragAndDrop(IBinder dragToken) {}
+ }
+
+ /**
* Request that the window manager call
* {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
* within a surface transaction at a later time.
@@ -225,9 +250,6 @@ public abstract class WindowManagerInternal {
*/
public abstract boolean isKeyguardLocked();
- /** @return {@code true} if the keyguard is going away. */
- public abstract boolean isKeyguardGoingAway();
-
/**
* @return Whether the keyguard is showing and not occluded.
*/
@@ -354,4 +376,9 @@ public abstract class WindowManagerInternal {
* {@param vr2dDisplayId}.
*/
public abstract void setVr2dDisplayId(int vr2dDisplayId);
+
+ /**
+ * Sets callback to DragDropController.
+ */
+ public abstract void registerDragDropControllerCallback(IDragDropCallback callback);
}
diff --git a/android/view/WindowManagerPolicy.java b/android/view/WindowManagerPolicy.java
index 137e551d..534335bf 100644
--- a/android/view/WindowManagerPolicy.java
+++ b/android/view/WindowManagerPolicy.java
@@ -66,7 +66,6 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
@@ -722,12 +721,6 @@ public interface WindowManagerPolicy {
public void setInitialDisplaySize(Display display, int width, int height, int density);
/**
- * Called by window manager to set the overscan region that should be used for the
- * given display.
- */
- public void setDisplayOverscan(Display display, int left, int top, int right, int bottom);
-
- /**
* Check permissions when adding a window.
*
* @param attrs The window's LayoutParams.
@@ -758,7 +751,8 @@ public interface WindowManagerPolicy {
* @param attrs The window layout parameters to be modified. These values
* are modified in-place.
*/
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs);
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission);
/**
* After the window manager has computed the current configuration based
@@ -1172,14 +1166,10 @@ public interface WindowManagerPolicy {
/**
* Called when layout of the windows is about to start.
*
- * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}.
- * @param displayWidth The current full width of the screen.
- * @param displayHeight The current full height of the screen.
- * @param displayRotation The current rotation being applied to the base window.
+ * @param displayFrames frames of the display we are doing layout on.
* @param uiMode The current uiMode in configuration.
*/
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
- int displayRotation, int uiMode);
+ default void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {}
/**
* Returns the bottom-most layer of the system decor, above which no policy decor should
@@ -1188,37 +1178,28 @@ public interface WindowManagerPolicy {
public int getSystemDecorLayerLw();
/**
- * Return the rectangle of the screen that is available for applications to run in.
- * This will be called immediately after {@link #beginLayoutLw}.
- *
- * @param r The rectangle to be filled with the boundaries available to applications.
- */
- public void getContentRectLw(Rect r);
-
- /**
- * Called for each window attached to the window manager as layout is
- * proceeding. The implementation of this function must take care of
- * setting the window's frame, either here or in finishLayout().
+ * Called for each window attached to the window manager as layout is proceeding. The
+ * implementation of this function must take care of setting the window's frame, either here or
+ * in finishLayout().
*
* @param win The window being positioned.
* @param attached For sub-windows, the window it is attached to; this
* window will already have had layoutWindow() called on it
* so you can use its Rect. Otherwise null.
+ * @param displayFrames The display frames.
*/
- public void layoutWindowLw(WindowState win, WindowState attached);
+ default void layoutWindowLw(
+ WindowState win, WindowState attached, DisplayFrames displayFrames) {}
/**
- * Return the insets for the areas covered by system windows. These values
- * are computed on the most recent layout, so they are not guaranteed to
- * be correct.
+ * Return the insets for the areas covered by system windows. These values are computed on the
+ * most recent layout, so they are not guaranteed to be correct.
*
* @param attrs The LayoutParams of the window.
* @param taskBounds The bounds of the task this window is on or {@code null} if no task is
* associated with the window.
- * @param displayRotation Rotation of the display.
- * @param displayWidth The width of the display.
- * @param displayHeight The height of the display.
+ * @param displayFrames display frames.
* @param outContentInsets The areas covered by system windows, expressed as positive insets.
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
@@ -1226,16 +1207,11 @@ public interface WindowManagerPolicy {
* @return Whether to always consume the navigation bar.
* See {@link #isNavBarForcedShownLw(WindowState)}.
*/
- public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- int displayRotation, int displayWidth, int displayHeight, Rect outContentInsets,
- Rect outStableInsets, Rect outOutsets);
-
- /**
- * Called when layout of the windows is finished. After this function has
- * returned, all windows given to layoutWindow() <em>must</em> have had a
- * frame assigned.
- */
- public void finishLayoutLw();
+ default boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
+ DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
+ Rect outOutsets) {
+ return false;
+ }
/** Layout state may have changed (so another layout will be performed) */
static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
@@ -1652,11 +1628,6 @@ public interface WindowManagerPolicy {
public void showGlobalActions();
/**
- * @return The current height of the input method window.
- */
- public int getInputMethodWindowVisibleHeightLw();
-
- /**
* Called when the current user changes. Guaranteed to be called before the broadcast
* of the new user id is made to all listeners.
*
diff --git a/android/view/accessibility/AccessibilityInteractionClient.java b/android/view/accessibility/AccessibilityInteractionClient.java
index 19213ca0..c3d6c695 100644
--- a/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/android/view/accessibility/AccessibilityInteractionClient.java
@@ -187,8 +187,11 @@ public final class AccessibilityInteractionClient
Log.i(LOG_TAG, "Window cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
- window = connection.getWindow(accessibilityWindowId);
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ window = connection.getWindow(accessibilityWindowId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (window != null) {
sAccessibilityCache.addWindow(window);
return window;
@@ -225,8 +228,11 @@ public final class AccessibilityInteractionClient
Log.i(LOG_TAG, "Windows cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
- windows = connection.getWindows();
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ windows = connection.getWindows();
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (windows != null) {
sAccessibilityCache.setWindows(windows);
return windows;
@@ -283,10 +289,14 @@ public final class AccessibilityInteractionClient
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
- accessibilityWindowId, accessibilityNodeId, interactionId, this,
- prefetchFlags, Thread.currentThread().getId(), arguments);
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityWindowId, accessibilityNodeId, interactionId, this,
+ prefetchFlags, Thread.currentThread().getId(), arguments);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -333,10 +343,15 @@ public final class AccessibilityInteractionClient
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByViewId(
- accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfosByViewId(
+ accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -381,10 +396,15 @@ public final class AccessibilityInteractionClient
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByText(
- accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfosByText(
+ accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -428,10 +448,15 @@ public final class AccessibilityInteractionClient
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findFocus(accessibilityWindowId,
- accessibilityNodeId, focusType, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findFocus(accessibilityWindowId,
+ accessibilityNodeId, focusType, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
@@ -472,10 +497,15 @@ public final class AccessibilityInteractionClient
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.focusSearch(accessibilityWindowId,
- accessibilityNodeId, direction, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.focusSearch(accessibilityWindowId,
+ accessibilityNodeId, direction, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
@@ -515,10 +545,15 @@ public final class AccessibilityInteractionClient
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.performAccessibilityAction(
- accessibilityWindowId, accessibilityNodeId, action, arguments,
- interactionId, this, Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.performAccessibilityAction(
+ accessibilityWindowId, accessibilityNodeId, action, arguments,
+ interactionId, this, Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
return getPerformAccessibilityActionResultAndClear(interactionId);
}
diff --git a/android/view/accessibility/AccessibilityManager.java b/android/view/accessibility/AccessibilityManager.java
index 0b9bc576..35f6acba 100644
--- a/android/view/accessibility/AccessibilityManager.java
+++ b/android/view/accessibility/AccessibilityManager.java
@@ -436,8 +436,11 @@ public final class AccessibilityManager {
// client using it is called through Binder from another process. Example: MMS
// app adds a SMS notification and the NotificationManagerService calls this method
long identityToken = Binder.clearCallingIdentity();
- service.sendAccessibilityEvent(event, userId);
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ service.sendAccessibilityEvent(event, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (DEBUG) {
Log.i(LOG_TAG, event + " sent");
}
diff --git a/android/view/autofill/AutofillManager.java b/android/view/autofill/AutofillManager.java
index e79d201b..9241ec00 100644
--- a/android/view/autofill/AutofillManager.java
+++ b/android/view/autofill/AutofillManager.java
@@ -54,6 +54,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+// TODO: use java.lang.ref.Cleaner once Android supports Java 9
+import sun.misc.Cleaner;
+
/**
* The {@link AutofillManager} provides ways for apps and custom views to integrate with the
* Autofill Framework lifecycle.
@@ -303,6 +306,9 @@ public final class AutofillManager {
private IAutoFillManagerClient mServiceClient;
@GuardedBy("mLock")
+ private Cleaner mServiceClientCleaner;
+
+ @GuardedBy("mLock")
private AutofillCallback mCallback;
private final Context mContext;
@@ -1172,10 +1178,19 @@ public final class AutofillManager {
if (mServiceClient == null) {
mServiceClient = new AutofillManagerClient(this);
try {
- final int flags = mService.addClient(mServiceClient, mContext.getUserId());
+ final int userId = mContext.getUserId();
+ final int flags = mService.addClient(mServiceClient, userId);
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
+ final IAutoFillManager service = mService;
+ final IAutoFillManagerClient serviceClient = mServiceClient;
+ mServiceClientCleaner = Cleaner.create(this, () -> {
+ try {
+ service.removeClient(serviceClient, userId);
+ } catch (RemoteException e) {
+ }
+ });
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1272,18 +1287,36 @@ public final class AutofillManager {
}
}
- private void setState(boolean enabled, boolean resetSession, boolean resetClient) {
+ /** @hide */
+ public static final int SET_STATE_FLAG_ENABLED = 0x01;
+ /** @hide */
+ public static final int SET_STATE_FLAG_RESET_SESSION = 0x02;
+ /** @hide */
+ public static final int SET_STATE_FLAG_RESET_CLIENT = 0x04;
+ /** @hide */
+ public static final int SET_STATE_FLAG_DEBUG = 0x08;
+ /** @hide */
+ public static final int SET_STATE_FLAG_VERBOSE = 0x10;
+
+ private void setState(int flags) {
+ if (sVerbose) Log.v(TAG, "setState(" + flags + ")");
synchronized (mLock) {
- mEnabled = enabled;
- if (!mEnabled || resetSession) {
+ mEnabled = (flags & SET_STATE_FLAG_ENABLED) != 0;
+ if (!mEnabled || (flags & SET_STATE_FLAG_RESET_SESSION) != 0) {
// Reset the session state
resetSessionLocked();
}
- if (resetClient) {
+ if ((flags & SET_STATE_FLAG_RESET_CLIENT) != 0) {
// Reset connection to system
mServiceClient = null;
+ if (mServiceClientCleaner != null) {
+ mServiceClientCleaner.clean();
+ mServiceClientCleaner = null;
+ }
}
}
+ sDebug = (flags & SET_STATE_FLAG_DEBUG) != 0;
+ sVerbose = (flags & SET_STATE_FLAG_VERBOSE) != 0;
}
/**
@@ -1609,6 +1642,7 @@ public final class AutofillManager {
pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
pw.print(pfx); pw.print("context: "); pw.println(mContext);
+ pw.print(pfx); pw.print("client: "); pw.println(getClientLocked());
pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1625,6 +1659,8 @@ public final class AutofillManager {
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
+ pw.print(pfx); pw.print("debug: "); pw.print(sDebug);
+ pw.print(" verbose: "); pw.println(sVerbose);
}
private String getStateAsStringLocked() {
@@ -1880,7 +1916,7 @@ public final class AutofillManager {
public abstract static class AutofillCallback {
/** @hide */
- @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN})
+ @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillEventType {}
@@ -1940,10 +1976,10 @@ public final class AutofillManager {
}
@Override
- public void setState(boolean enabled, boolean resetSession, boolean resetClient) {
+ public void setState(int flags) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() -> afm.setState(enabled, resetSession, resetClient));
+ afm.post(() -> afm.setState(flags));
}
}
diff --git a/android/view/textclassifier/TextClassification.java b/android/view/textclassifier/TextClassification.java
index 26d2141e..2779aa2d 100644
--- a/android/view/textclassifier/TextClassification.java
+++ b/android/view/textclassifier/TextClassification.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.os.LocaleList;
import android.view.View.OnClickListener;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -438,4 +439,31 @@ public final class TextClassification {
mLogType, mVersionInfo);
}
}
+
+ /**
+ * TextClassification optional input parameters.
+ */
+ public static final class Options {
+
+ private LocaleList mDefaultLocales;
+
+ /**
+ * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+ * the provided text. If no locale preferences exist, set this to null or an empty
+ * locale list.
+ */
+ public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+ mDefaultLocales = defaultLocales;
+ return this;
+ }
+
+ /**
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
+ */
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
+ }
+ }
}
diff --git a/android/view/textclassifier/TextClassifier.java b/android/view/textclassifier/TextClassifier.java
index 46dbd0e3..aeb84897 100644
--- a/android/view/textclassifier/TextClassifier.java
+++ b/android/view/textclassifier/TextClassifier.java
@@ -56,23 +56,7 @@ public interface TextClassifier {
* No-op TextClassifier.
* This may be used to turn off TextClassifier features.
*/
- TextClassifier NO_OP = new TextClassifier() {
-
- @Override
- public TextSelection suggestSelection(
- CharSequence text,
- int selectionStartIndex,
- int selectionEndIndex,
- LocaleList defaultLocales) {
- return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
- }
-
- @Override
- public TextClassification classifyText(
- CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
- return TextClassification.EMPTY;
- }
- };
+ TextClassifier NO_OP = new TextClassifier() {};
/**
* Returns suggested text selection start and end indices, recognized entity types, and their
@@ -82,21 +66,34 @@ public interface TextClassifier {
* by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
* @param selectionStartIndex start index of the selected part of text
* @param selectionEndIndex end index of the selected part of text
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
* selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
*/
@WorkerThread
@NonNull
- TextSelection suggestSelection(
+ default TextSelection suggestSelection(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int selectionStartIndex,
+ @IntRange(from = 0) int selectionEndIndex,
+ @Nullable TextSelection.Options options) {
+ return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ }
+
+ /**
+ * @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
+ */
+ // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextSelection suggestSelection(
@NonNull CharSequence text,
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
- @Nullable LocaleList defaultLocales);
+ @Nullable LocaleList defaultLocales) {
+ return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ }
/**
* Classifies the specified text and returns a {@link TextClassification} object that can be
@@ -106,41 +103,48 @@ public interface TextClassifier {
* by the sub sequence starting at startIndex and ending at endIndex)
* @param startIndex start index of the text to classify
* @param endIndex end index of the text to classify
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or not greater than startIndex
*/
@WorkerThread
@NonNull
- TextClassification classifyText(
+ default TextClassification classifyText(
@NonNull CharSequence text,
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
- @Nullable LocaleList defaultLocales);
+ @Nullable TextClassification.Options options) {
+ return TextClassification.EMPTY;
+ }
/**
- * Returns a {@link LinksInfo} that may be applied to the text to annotate it with links
+ * @see #classifyText(CharSequence, int, int, TextClassification.Options)
+ */
+ // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextClassification classifyText(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int startIndex,
+ @IntRange(from = 0) int endIndex,
+ @Nullable LocaleList defaultLocales) {
+ return TextClassification.EMPTY;
+ }
+
+ /**
+ * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
* information.
*
* @param text the text to generate annotations for
- * @param linkMask See {@link android.text.util.Linkify} for a list of linkMasks that may be
- * specified. Subclasses of this interface may specify additional linkMasks
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options configuration for link generation. If null, defaults will be used.
*
* @throws IllegalArgumentException if text is null
- * @hide
*/
@WorkerThread
- default LinksInfo getLinks(
- @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
- return LinksInfo.NO_OP;
+ default TextLinks generateLinks(
+ @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ return new TextLinks.Builder(text.toString()).build();
}
/**
diff --git a/android/view/textclassifier/TextClassifierImpl.java b/android/view/textclassifier/TextClassifierImpl.java
index 1c07be4b..2ad6e02c 100644
--- a/android/view/textclassifier/TextClassifierImpl.java
+++ b/android/view/textclassifier/TextClassifierImpl.java
@@ -30,13 +30,8 @@ import android.os.ParcelFileDescriptor;
import android.provider.Browser;
import android.provider.ContactsContract;
import android.provider.Settings;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.text.method.WordIterator;
-import android.text.style.ClickableSpan;
import android.text.util.Linkify;
import android.util.Patterns;
-import android.view.View;
import android.widget.TextViewMetrics;
import com.android.internal.annotations.GuardedBy;
@@ -46,13 +41,8 @@ import com.android.internal.util.Preconditions;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.text.BreakIterator;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -100,16 +90,24 @@ final class TextClassifierImpl implements TextClassifier {
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable LocaleList defaultLocales) {
+ @Nullable TextSelection.Options options) {
validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
- final SmartSelection smartSelection = getSmartSelection(defaultLocales);
+ final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
+ final SmartSelection smartSelection = getSmartSelection(locales);
final String string = text.toString();
- final int[] startEnd = smartSelection.suggest(
- string, selectionStartIndex, selectionEndIndex);
- final int start = startEnd[0];
- final int end = startEnd[1];
+ final int start;
+ final int end;
+ if (getSettings().isDarkLaunch() && !options.isDarkLaunchAllowed()) {
+ start = selectionStartIndex;
+ end = selectionEndIndex;
+ } else {
+ final int[] startEnd = smartSelection.suggest(
+ string, selectionStartIndex, selectionEndIndex);
+ start = startEnd[0];
+ end = startEnd[1];
+ }
if (start <= end
&& start >= 0 && end <= string.length()
&& start <= selectionStartIndex && end >= selectionEndIndex) {
@@ -139,18 +137,27 @@ final class TextClassifierImpl implements TextClassifier {
}
// Getting here means something went wrong, return a NO_OP result.
return TextClassifier.NO_OP.suggestSelection(
- text, selectionStartIndex, selectionEndIndex, defaultLocales);
+ text, selectionStartIndex, selectionEndIndex, options);
+ }
+
+ @Override
+ public TextSelection suggestSelection(
+ @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
+ @Nullable LocaleList defaultLocales) {
+ return suggestSelection(text, selectionStartIndex, selectionEndIndex,
+ new TextSelection.Options().setDefaultLocales(defaultLocales));
}
@Override
public TextClassification classifyText(
@NonNull CharSequence text, int startIndex, int endIndex,
- @Nullable LocaleList defaultLocales) {
+ @Nullable TextClassification.Options options) {
validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
final String string = text.toString();
- SmartSelection.ClassificationResult[] results = getSmartSelection(defaultLocales)
+ final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
+ final SmartSelection.ClassificationResult[] results = getSmartSelection(locales)
.classifyText(string, startIndex, endIndex,
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
@@ -165,23 +172,41 @@ final class TextClassifierImpl implements TextClassifier {
Log.e(LOG_TAG, "Error getting text classification info.", t);
}
// Getting here means something went wrong, return a NO_OP result.
- return TextClassifier.NO_OP.classifyText(
- text, startIndex, endIndex, defaultLocales);
+ return TextClassifier.NO_OP.classifyText(text, startIndex, endIndex, options);
}
@Override
- public LinksInfo getLinks(
- @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
- Preconditions.checkArgument(text != null);
+ public TextClassification classifyText(
+ @NonNull CharSequence text, int startIndex, int endIndex,
+ @Nullable LocaleList defaultLocales) {
+ return classifyText(text, startIndex, endIndex,
+ new TextClassification.Options().setDefaultLocales(defaultLocales));
+ }
+
+ @Override
+ public TextLinks generateLinks(
+ @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ Preconditions.checkNotNull(text);
+ final String textString = text.toString();
+ final TextLinks.Builder builder = new TextLinks.Builder(textString);
try {
- return LinksInfoFactory.create(
- mContext, getSmartSelection(defaultLocales), text.toString(), linkMask);
+ LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
+ final SmartSelection smartSelection = getSmartSelection(defaultLocales);
+ final SmartSelection.AnnotatedSpan[] annotations = smartSelection.annotate(textString);
+ for (SmartSelection.AnnotatedSpan span : annotations) {
+ final Map<String, Float> entityScores = new HashMap<>();
+ final SmartSelection.ClassificationResult[] results = span.getClassification();
+ for (int i = 0; i < results.length; i++) {
+ entityScores.put(results[i].mCollection, results[i].mScore);
+ }
+ builder.addLink(new TextLinks.TextLink(
+ textString, span.getStartIndex(), span.getEndIndex(), entityScores));
+ }
} catch (Throwable t) {
// Avoid throwing from this method. Log the error.
Log.e(LOG_TAG, "Error getting links info.", t);
}
- // Getting here means something went wrong, return a NO_OP result.
- return TextClassifier.NO_OP.getLinks(text, linkMask, defaultLocales);
+ return builder.build();
}
@Override
@@ -210,7 +235,9 @@ final class TextClassifierImpl implements TextClassifier {
if (mSmartSelection == null || !Objects.equals(mLocale, locale)) {
destroySmartSelectionIfExistsLocked();
final ParcelFileDescriptor fd = getFdLocked(locale);
- mSmartSelection = new SmartSelection(fd.getFd());
+ final int modelFd = fd.getFd();
+ mVersion = SmartSelection.getVersion(modelFd);
+ mSmartSelection = new SmartSelection(modelFd);
closeAndLogError(fd);
mLocale = locale;
}
@@ -231,18 +258,26 @@ final class TextClassifierImpl implements TextClassifier {
@GuardedBy("mSmartSelectionLock") // Do not call outside this lock.
private ParcelFileDescriptor getFdLocked(Locale locale) throws FileNotFoundException {
ParcelFileDescriptor updateFd;
+ int updateVersion = -1;
try {
updateFd = ParcelFileDescriptor.open(
new File(UPDATED_MODEL_FILE_PATH), ParcelFileDescriptor.MODE_READ_ONLY);
+ if (updateFd != null) {
+ updateVersion = SmartSelection.getVersion(updateFd.getFd());
+ }
} catch (FileNotFoundException e) {
updateFd = null;
}
ParcelFileDescriptor factoryFd;
+ int factoryVersion = -1;
try {
final String factoryModelFilePath = getFactoryModelFilePathsLocked().get(locale);
if (factoryModelFilePath != null) {
factoryFd = ParcelFileDescriptor.open(
new File(factoryModelFilePath), ParcelFileDescriptor.MODE_READ_ONLY);
+ if (factoryFd != null) {
+ factoryVersion = SmartSelection.getVersion(factoryFd.getFd());
+ }
} else {
factoryFd = null;
}
@@ -278,15 +313,11 @@ final class TextClassifierImpl implements TextClassifier {
return factoryFd;
}
- final int updateVersion = SmartSelection.getVersion(updateFdInt);
- final int factoryVersion = SmartSelection.getVersion(factoryFd.getFd());
if (updateVersion > factoryVersion) {
closeAndLogError(factoryFd);
- mVersion = updateVersion;
return updateFd;
} else {
closeAndLogError(updateFd);
- mVersion = factoryVersion;
return factoryFd;
}
}
@@ -466,180 +497,6 @@ final class TextClassifierImpl implements TextClassifier {
}
/**
- * Detects and creates links for specified text.
- */
- private static final class LinksInfoFactory {
-
- private LinksInfoFactory() {}
-
- public static LinksInfo create(
- Context context, SmartSelection smartSelection, String text, int linkMask) {
- final WordIterator wordIterator = new WordIterator();
- wordIterator.setCharSequence(text, 0, text.length());
- final List<SpanSpec> spans = new ArrayList<>();
- int start = 0;
- int end;
- while ((end = wordIterator.nextBoundary(start)) != BreakIterator.DONE) {
- final String token = text.substring(start, end);
- if (TextUtils.isEmpty(token)) {
- continue;
- }
-
- final int[] selection = smartSelection.suggest(text, start, end);
- final int selectionStart = selection[0];
- final int selectionEnd = selection[1];
- if (selectionStart >= 0 && selectionEnd <= text.length()
- && selectionStart <= selectionEnd) {
- final SmartSelection.ClassificationResult[] results =
- smartSelection.classifyText(
- text, selectionStart, selectionEnd,
- getHintFlags(text, selectionStart, selectionEnd));
- if (results.length > 0) {
- final String type = getHighestScoringType(results);
- if (matches(type, linkMask)) {
- // For links without disambiguation, we simply use the default intent.
- final List<Intent> intents = IntentFactory.create(
- context, type, text.substring(selectionStart, selectionEnd));
- if (!intents.isEmpty() && hasActivityHandler(context, intents.get(0))) {
- final ClickableSpan span = createSpan(context, intents.get(0));
- spans.add(new SpanSpec(selectionStart, selectionEnd, span));
- }
- }
- }
- }
- start = end;
- }
- return new LinksInfoImpl(text, avoidOverlaps(spans, text));
- }
-
- /**
- * Returns true if the classification type matches the specified linkMask.
- */
- private static boolean matches(String type, int linkMask) {
- type = type.trim().toLowerCase(Locale.ENGLISH);
- if ((linkMask & Linkify.PHONE_NUMBERS) != 0
- && TextClassifier.TYPE_PHONE.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.EMAIL_ADDRESSES) != 0
- && TextClassifier.TYPE_EMAIL.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.MAP_ADDRESSES) != 0
- && TextClassifier.TYPE_ADDRESS.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.WEB_URLS) != 0
- && TextClassifier.TYPE_URL.equals(type)) {
- return true;
- }
- return false;
- }
-
- /**
- * Trim the number of spans so that no two spans overlap.
- *
- * This algorithm first ensures that there is only one span per start index, then it
- * makes sure that no two spans overlap.
- */
- private static List<SpanSpec> avoidOverlaps(List<SpanSpec> spans, String text) {
- Collections.sort(spans, Comparator.comparingInt(span -> span.mStart));
- // Group spans by start index. Take the longest span.
- final Map<Integer, SpanSpec> reps = new LinkedHashMap<>(); // order matters.
- final int size = spans.size();
- for (int i = 0; i < size; i++) {
- final SpanSpec span = spans.get(i);
- final LinksInfoFactory.SpanSpec rep = reps.get(span.mStart);
- if (rep == null || rep.mEnd < span.mEnd) {
- reps.put(span.mStart, span);
- }
- }
- // Avoid span intersections. Take the longer span.
- final LinkedList<SpanSpec> result = new LinkedList<>();
- for (SpanSpec rep : reps.values()) {
- if (result.isEmpty()) {
- result.add(rep);
- continue;
- }
-
- final SpanSpec last = result.getLast();
- if (rep.mStart < last.mEnd) {
- // Spans intersect. Use the one with characters.
- if ((rep.mEnd - rep.mStart) > (last.mEnd - last.mStart)) {
- result.set(result.size() - 1, rep);
- }
- } else {
- result.add(rep);
- }
- }
- return result;
- }
-
- private static ClickableSpan createSpan(final Context context, final Intent intent) {
- return new ClickableSpan() {
- // TODO: Style this span.
- @Override
- public void onClick(View widget) {
- context.startActivity(intent);
- }
- };
- }
-
- private static boolean hasActivityHandler(Context context, Intent intent) {
- if (intent == null) {
- return false;
- }
- final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
- return resolveInfo != null && resolveInfo.activityInfo != null;
- }
-
- /**
- * Implementation of LinksInfo that adds ClickableSpans to the specified text.
- */
- private static final class LinksInfoImpl implements LinksInfo {
-
- private final CharSequence mOriginalText;
- private final List<SpanSpec> mSpans;
-
- LinksInfoImpl(CharSequence originalText, List<SpanSpec> spans) {
- mOriginalText = originalText;
- mSpans = spans;
- }
-
- @Override
- public boolean apply(@NonNull CharSequence text) {
- Preconditions.checkArgument(text != null);
- if (text instanceof Spannable && mOriginalText.toString().equals(text.toString())) {
- Spannable spannable = (Spannable) text;
- final int size = mSpans.size();
- for (int i = 0; i < size; i++) {
- final SpanSpec span = mSpans.get(i);
- spannable.setSpan(span.mSpan, span.mStart, span.mEnd, 0);
- }
- return true;
- }
- return false;
- }
- }
-
- /**
- * Span plus its start and end index.
- */
- private static final class SpanSpec {
-
- private final int mStart;
- private final int mEnd;
- private final ClickableSpan mSpan;
-
- SpanSpec(int start, int end, ClickableSpan span) {
- mStart = start;
- mEnd = end;
- mSpan = span;
- }
- }
- }
-
- /**
* Creates intents based on the classification type.
*/
private static final class IntentFactory {
@@ -656,8 +513,8 @@ final class TextClassifierImpl implements TextClassifier {
intents.add(new Intent(Intent.ACTION_SENDTO)
.setData(Uri.parse(String.format("mailto:%s", text))));
intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
break;
case TextClassifier.TYPE_PHONE:
intents.add(new Intent(Intent.ACTION_DIAL)
diff --git a/android/view/textclassifier/TextLinks.java b/android/view/textclassifier/TextLinks.java
new file mode 100644
index 00000000..f3cc827f
--- /dev/null
+++ b/android/view/textclassifier/TextLinks.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.LocaleList;
+import android.text.SpannableString;
+import android.text.style.ClickableSpan;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A collection of links, representing subsequences of text and the entity types (phone number,
+ * address, url, etc) they may be.
+ */
+public final class TextLinks {
+ private final String mFullText;
+ private final List<TextLink> mLinks;
+
+ private TextLinks(String fullText, Collection<TextLink> links) {
+ mFullText = fullText;
+ mLinks = Collections.unmodifiableList(new ArrayList<>(links));
+ }
+
+ /**
+ * Returns an unmodifiable Collection of the links.
+ */
+ public Collection<TextLink> getLinks() {
+ return mLinks;
+ }
+
+ /**
+ * Annotates the given text with the generated links. It will fail if the provided text doesn't
+ * match the original text used to crete the TextLinks.
+ *
+ * @param text the text to apply the links to. Must match the original text.
+ * @param spanFactory a factory to generate spans from TextLinks. Will use a default if null.
+ *
+ * @return Success or failure.
+ */
+ public boolean apply(
+ @NonNull SpannableString text,
+ @Nullable Function<TextLink, ClickableSpan> spanFactory) {
+ Preconditions.checkNotNull(text);
+ if (!mFullText.equals(text.toString())) {
+ return false;
+ }
+
+ if (spanFactory == null) {
+ spanFactory = DEFAULT_SPAN_FACTORY;
+ }
+ for (TextLink link : mLinks) {
+ final ClickableSpan span = spanFactory.apply(link);
+ if (span != null) {
+ text.setSpan(span, link.getStart(), link.getEnd(), 0);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A link, identifying a substring of text and possible entity types for it.
+ */
+ public static final class TextLink {
+ private final EntityConfidence<String> mEntityScores;
+ private final String mOriginalText;
+ private final int mStart;
+ private final int mEnd;
+
+ /**
+ * Create a new TextLink.
+ *
+ * @throws IllegalArgumentException if entityScores is null or empty.
+ */
+ public TextLink(String originalText, int start, int end, Map<String, Float> entityScores) {
+ Preconditions.checkNotNull(originalText);
+ Preconditions.checkNotNull(entityScores);
+ Preconditions.checkArgument(!entityScores.isEmpty());
+ Preconditions.checkArgument(start <= end);
+ mOriginalText = originalText;
+ mStart = start;
+ mEnd = end;
+ mEntityScores = new EntityConfidence<>();
+
+ for (Map.Entry<String, Float> entry : entityScores.entrySet()) {
+ mEntityScores.setEntityType(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Returns the start index of this link in the original text.
+ *
+ * @return the start index.
+ */
+ public int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Returns the end index of this link in the original text.
+ *
+ * @return the end index.
+ */
+ public int getEnd() {
+ return mEnd;
+ }
+
+ /**
+ * Returns the number of entity types that have confidence scores.
+ *
+ * @return the entity count.
+ */
+ public int getEntityCount() {
+ return mEntityScores.getEntities().size();
+ }
+
+ /**
+ * Returns the entity type at a given index. Entity types are sorted by confidence.
+ *
+ * @return the entity type at the provided index.
+ */
+ @NonNull public @TextClassifier.EntityType String getEntity(int index) {
+ return mEntityScores.getEntities().get(index);
+ }
+
+ /**
+ * Returns the confidence score for a particular entity type.
+ *
+ * @param entityType the entity type.
+ */
+ public @FloatRange(from = 0.0, to = 1.0) float getConfidenceScore(
+ @TextClassifier.EntityType String entityType) {
+ return mEntityScores.getConfidenceScore(entityType);
+ }
+ }
+
+ /**
+ * Optional input parameters for generating TextLinks.
+ */
+ public static final class Options {
+ private final LocaleList mLocaleList;
+
+ private Options(LocaleList localeList) {
+ this.mLocaleList = localeList;
+ }
+
+ /**
+ * Builder to construct Options.
+ */
+ public static final class Builder {
+ private LocaleList mLocaleList;
+
+ /**
+ * Sets the LocaleList to use.
+ *
+ * @return this Builder.
+ */
+ public Builder setLocaleList(@Nullable LocaleList localeList) {
+ this.mLocaleList = localeList;
+ return this;
+ }
+
+ /**
+ * Builds the Options object.
+ */
+ public Options build() {
+ return new Options(mLocaleList);
+ }
+ }
+ public @Nullable LocaleList getDefaultLocales() {
+ return mLocaleList;
+ }
+ };
+
+ /**
+ * A function to create spans from TextLinks.
+ *
+ * Applies only to TextViews.
+ * We can hide this until we are convinced we want it to be part of the public API.
+ *
+ * @hide
+ */
+ public static final Function<TextLink, ClickableSpan> DEFAULT_SPAN_FACTORY =
+ new Function<TextLink, ClickableSpan>() {
+ @Override
+ public ClickableSpan apply(TextLink textLink) {
+ // TODO: Implement.
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+ };
+
+ /**
+ * A builder to construct a TextLinks instance.
+ */
+ public static final class Builder {
+ private final String mFullText;
+ private final Collection<TextLink> mLinks;
+
+ /**
+ * Create a new TextLinks.Builder.
+ *
+ * @param fullText The full text that links will be added to.
+ */
+ public Builder(@NonNull String fullText) {
+ mFullText = Preconditions.checkNotNull(fullText);
+ mLinks = new ArrayList<>();
+ }
+
+ /**
+ * Adds a TextLink.
+ *
+ * @return this instance.
+ */
+ public Builder addLink(TextLink link) {
+ Preconditions.checkNotNull(link);
+ mLinks.add(link);
+ return this;
+ }
+
+ /**
+ * Constructs a TextLinks instance.
+ *
+ * @return the constructed TextLinks.
+ */
+ public TextLinks build() {
+ return new TextLinks(mFullText, mLinks);
+ }
+ }
+}
diff --git a/android/view/textclassifier/TextSelection.java b/android/view/textclassifier/TextSelection.java
index 11ebe835..0a67954a 100644
--- a/android/view/textclassifier/TextSelection.java
+++ b/android/view/textclassifier/TextSelection.java
@@ -19,6 +19,8 @@ package android.view.textclassifier;
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.LocaleList;
import android.view.textclassifier.TextClassifier.EntityType;
import com.android.internal.util.Preconditions;
@@ -181,4 +183,55 @@ public final class TextSelection {
mStartIndex, mEndIndex, mEntityConfidence, mLogSource, mVersionInfo);
}
}
+
+ /**
+ * TextSelection optional input parameters.
+ */
+ public static final class Options {
+
+ private LocaleList mDefaultLocales;
+ private boolean mDarkLaunchAllowed;
+
+ /**
+ * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+ * the provided text. If no locale preferences exist, set this to null or an empty
+ * locale list.
+ */
+ public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+ mDefaultLocales = defaultLocales;
+ return this;
+ }
+
+ /**
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
+ */
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
+ }
+
+ /**
+ * @param allowed whether or not the TextClassifier should return selection suggestions
+ * when "dark launched". When a TextClassifier is dark launched, it can suggest
+ * selection changes that should not be used to actually change the user's selection.
+ * Instead, the suggested selection is logged, compared with the user's selection
+ * interaction, and used to generate quality metrics for the TextClassifier.
+ *
+ * @hide
+ */
+ public void setDarkLaunchAllowed(boolean allowed) {
+ mDarkLaunchAllowed = allowed;
+ }
+
+ /**
+ * Returns true if the TextClassifier should return selection suggestions when
+ * "dark launched". Otherwise, returns false.
+ *
+ * @hide
+ */
+ public boolean isDarkLaunchAllowed() {
+ return mDarkLaunchAllowed;
+ }
+ }
}
diff --git a/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index 83af19bb..2833564f 100644
--- a/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -48,31 +48,45 @@ public final class SmartSelectionEventTracker {
private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
private static final int INDEX = MetricsEvent.FIELD_SELECTION_SESSION_INDEX;
- private static final int VERSION_TAG = MetricsEvent.FIELD_SELECTION_VERSION_TAG;
- private static final int SMART_INDICES = MetricsEvent.FIELD_SELECTION_SMART_RANGE;
- private static final int EVENT_INDICES = MetricsEvent.FIELD_SELECTION_RANGE;
+ private static final int WIDGET_TYPE = MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
+ private static final int WIDGET_VERSION = MetricsEvent.FIELD_SELECTION_WIDGET_VERSION;
+ private static final int MODEL_NAME = MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
+ private static final int ENTITY_TYPE = MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
+ private static final int SMART_START = MetricsEvent.FIELD_SELECTION_SMART_RANGE_START;
+ private static final int SMART_END = MetricsEvent.FIELD_SELECTION_SMART_RANGE_END;
+ private static final int EVENT_START = MetricsEvent.FIELD_SELECTION_RANGE_START;
+ private static final int EVENT_END = MetricsEvent.FIELD_SELECTION_RANGE_END;
private static final int SESSION_ID = MetricsEvent.FIELD_SELECTION_SESSION_ID;
private static final String ZERO = "0";
private static final String TEXTVIEW = "textview";
private static final String EDITTEXT = "edittext";
+ private static final String UNSELECTABLE_TEXTVIEW = "nosel-textview";
private static final String WEBVIEW = "webview";
private static final String EDIT_WEBVIEW = "edit-webview";
+ private static final String CUSTOM_TEXTVIEW = "customview";
+ private static final String CUSTOM_EDITTEXT = "customedit";
+ private static final String CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
private static final String UNKNOWN = "unknown";
@Retention(RetentionPolicy.SOURCE)
@IntDef({WidgetType.UNSPECIFIED, WidgetType.TEXTVIEW, WidgetType.WEBVIEW,
WidgetType.EDITTEXT, WidgetType.EDIT_WEBVIEW})
public @interface WidgetType {
- int UNSPECIFIED = 0;
- int TEXTVIEW = 1;
- int WEBVIEW = 2;
- int EDITTEXT = 3;
- int EDIT_WEBVIEW = 4;
+ int UNSPECIFIED = 0;
+ int TEXTVIEW = 1;
+ int WEBVIEW = 2;
+ int EDITTEXT = 3;
+ int EDIT_WEBVIEW = 4;
+ int UNSELECTABLE_TEXTVIEW = 5;
+ int CUSTOM_TEXTVIEW = 6;
+ int CUSTOM_EDITTEXT = 7;
+ int CUSTOM_UNSELECTABLE_TEXTVIEW = 8;
}
private final MetricsLogger mMetricsLogger = new MetricsLogger();
private final int mWidgetType;
+ @Nullable private final String mWidgetVersion;
private final Context mContext;
@Nullable private String mSessionId;
@@ -83,10 +97,18 @@ public final class SmartSelectionEventTracker {
private long mSessionStartTime;
private long mLastEventTime;
private boolean mSmartSelectionTriggered;
- private String mVersionTag;
+ private String mModelName;
public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
mWidgetType = widgetType;
+ mWidgetVersion = null;
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ public SmartSelectionEventTracker(
+ @NonNull Context context, @WidgetType int widgetType, @Nullable String widgetVersion) {
+ mWidgetType = widgetType;
+ mWidgetVersion = widgetVersion;
mContext = Preconditions.checkNotNull(context);
}
@@ -115,7 +137,7 @@ public final class SmartSelectionEventTracker {
case SelectionEvent.EventType.SMART_SELECTION_SINGLE: // fall through
case SelectionEvent.EventType.SMART_SELECTION_MULTI:
mSmartSelectionTriggered = true;
- mVersionTag = getVersionTag(event);
+ mModelName = getModelName(event);
mSmartIndices[0] = event.mStart;
mSmartIndices[1] = event.mEnd;
break;
@@ -137,14 +159,19 @@ public final class SmartSelectionEventTracker {
final long prevEventDelta = mLastEventTime == 0 ? 0 : now - mLastEventTime;
final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
.setType(getLogType(event))
- .setSubtype(getLogSubType(event))
+ .setSubtype(MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL)
.setPackageName(mContext.getPackageName())
.addTaggedData(START_EVENT_DELTA, now - mSessionStartTime)
.addTaggedData(PREV_EVENT_DELTA, prevEventDelta)
.addTaggedData(INDEX, mIndex)
- .addTaggedData(VERSION_TAG, mVersionTag)
- .addTaggedData(SMART_INDICES, getSmartDelta())
- .addTaggedData(EVENT_INDICES, getEventDelta(event))
+ .addTaggedData(WIDGET_TYPE, getWidgetTypeName())
+ .addTaggedData(WIDGET_VERSION, mWidgetVersion)
+ .addTaggedData(MODEL_NAME, mModelName)
+ .addTaggedData(ENTITY_TYPE, event.mEntityType)
+ .addTaggedData(SMART_START, getSmartRangeDelta(mSmartIndices[0]))
+ .addTaggedData(SMART_END, getSmartRangeDelta(mSmartIndices[1]))
+ .addTaggedData(EVENT_START, getRangeDelta(event.mStart))
+ .addTaggedData(EVENT_END, getRangeDelta(event.mEnd))
.addTaggedData(SESSION_ID, mSessionId);
mMetricsLogger.write(log);
debugLog(log);
@@ -169,7 +196,7 @@ public final class SmartSelectionEventTracker {
mSessionStartTime = 0;
mLastEventTime = 0;
mSmartSelectionTriggered = false;
- mVersionTag = getVersionTag(null);
+ mModelName = getModelName(null);
mSessionId = null;
}
@@ -251,113 +278,75 @@ public final class SmartSelectionEventTracker {
}
}
- private static int getLogSubType(SelectionEvent event) {
- switch (event.mEntityType) {
- case TextClassifier.TYPE_OTHER:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_OTHER;
- case TextClassifier.TYPE_EMAIL:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_EMAIL;
- case TextClassifier.TYPE_PHONE:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_PHONE;
- case TextClassifier.TYPE_ADDRESS:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_ADDRESS;
- case TextClassifier.TYPE_URL:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_URL;
- default:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_UNKNOWN;
- }
- }
-
- private static String getLogSubTypeString(int logSubType) {
- switch (logSubType) {
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_OTHER:
- return TextClassifier.TYPE_OTHER;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_EMAIL:
- return TextClassifier.TYPE_EMAIL;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_PHONE:
- return TextClassifier.TYPE_PHONE;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_ADDRESS:
- return TextClassifier.TYPE_ADDRESS;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_URL:
- return TextClassifier.TYPE_URL;
- default:
- return TextClassifier.TYPE_UNKNOWN;
- }
- }
-
- private int getSmartDelta() {
- if (mSmartSelectionTriggered) {
- return (clamp(mSmartIndices[0] - mOrigStart) << 16)
- | (clamp(mSmartIndices[1] - mOrigStart) & 0xffff);
- }
- // If the smart selection model was not run, return invalid selection indices [0,0]. This
- // allows us to tell from the terminal event alone whether the model was run.
- return 0;
+ private int getRangeDelta(int offset) {
+ return offset - mOrigStart;
}
- private int getEventDelta(SelectionEvent event) {
- return (clamp(event.mStart - mOrigStart) << 16)
- | (clamp(event.mEnd - mOrigStart) & 0xffff);
+ private int getSmartRangeDelta(int offset) {
+ return mSmartSelectionTriggered ? getRangeDelta(offset) : 0;
}
- private String getVersionTag(@Nullable SelectionEvent event) {
- final String widgetType;
+ private String getWidgetTypeName() {
switch (mWidgetType) {
case WidgetType.TEXTVIEW:
- widgetType = TEXTVIEW;
- break;
+ return TEXTVIEW;
case WidgetType.WEBVIEW:
- widgetType = WEBVIEW;
- break;
+ return WEBVIEW;
case WidgetType.EDITTEXT:
- widgetType = EDITTEXT;
- break;
+ return EDITTEXT;
case WidgetType.EDIT_WEBVIEW:
- widgetType = EDIT_WEBVIEW;
- break;
+ return EDIT_WEBVIEW;
+ case WidgetType.UNSELECTABLE_TEXTVIEW:
+ return UNSELECTABLE_TEXTVIEW;
+ case WidgetType.CUSTOM_TEXTVIEW:
+ return CUSTOM_TEXTVIEW;
+ case WidgetType.CUSTOM_EDITTEXT:
+ return CUSTOM_EDITTEXT;
+ case WidgetType.CUSTOM_UNSELECTABLE_TEXTVIEW:
+ return CUSTOM_UNSELECTABLE_TEXTVIEW;
default:
- widgetType = UNKNOWN;
+ return UNKNOWN;
}
- final String version = event == null
+ }
+
+ private String getModelName(@Nullable SelectionEvent event) {
+ return event == null
? SelectionEvent.NO_VERSION_TAG
: Objects.toString(event.mVersionTag, SelectionEvent.NO_VERSION_TAG);
- return String.format("%s/%s", widgetType, version);
}
private static String createSessionId() {
return UUID.randomUUID().toString();
}
- private static int clamp(int val) {
- return Math.max(Math.min(val, Short.MAX_VALUE), Short.MIN_VALUE);
- }
-
private static void debugLog(LogMaker log) {
if (!DEBUG_LOG_ENABLED) return;
- final String tag = Objects.toString(log.getTaggedData(VERSION_TAG), "tag");
+ final String widgetType = Objects.toString(log.getTaggedData(WIDGET_TYPE), UNKNOWN);
+ final String widgetVersion = Objects.toString(log.getTaggedData(WIDGET_VERSION), "");
+ final String widget = widgetVersion.isEmpty()
+ ? widgetType : widgetType + "-" + widgetVersion;
final int index = Integer.parseInt(Objects.toString(log.getTaggedData(INDEX), ZERO));
if (log.getType() == MetricsEvent.ACTION_TEXT_SELECTION_START) {
String sessionId = Objects.toString(log.getTaggedData(SESSION_ID), "");
sessionId = sessionId.substring(sessionId.lastIndexOf("-") + 1);
- Log.d(LOG_TAG, String.format("New selection session: %s(%s)", tag, sessionId));
+ Log.d(LOG_TAG, String.format("New selection session: %s (%s)", widget, sessionId));
}
+ final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
+ final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
final String type = getLogTypeString(log.getType());
- final String subType = getLogSubTypeString(log.getSubtype());
-
- final int smartIndices = Integer.parseInt(
- Objects.toString(log.getTaggedData(SMART_INDICES), ZERO));
- final int smartStart = (short) ((smartIndices & 0xffff0000) >> 16);
- final int smartEnd = (short) (smartIndices & 0xffff);
-
- final int eventIndices = Integer.parseInt(
- Objects.toString(log.getTaggedData(EVENT_INDICES), ZERO));
- final int eventStart = (short) ((eventIndices & 0xffff0000) >> 16);
- final int eventEnd = (short) (eventIndices & 0xffff);
-
- Log.d(LOG_TAG, String.format("%2d: %s/%s, context=%d,%d - old=%d,%d (%s)",
- index, type, subType, eventStart, eventEnd, smartStart, smartEnd, tag));
+ final int smartStart = Integer.parseInt(
+ Objects.toString(log.getTaggedData(SMART_START), ZERO));
+ final int smartEnd = Integer.parseInt(
+ Objects.toString(log.getTaggedData(SMART_END), ZERO));
+ final int eventStart = Integer.parseInt(
+ Objects.toString(log.getTaggedData(EVENT_START), ZERO));
+ final int eventEnd = Integer.parseInt(
+ Objects.toString(log.getTaggedData(EVENT_END), ZERO));
+
+ Log.d(LOG_TAG, String.format("%2d: %s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
+ index, type, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model));
}
/**
@@ -369,12 +358,12 @@ public final class SmartSelectionEventTracker {
/**
* Use this to specify an indeterminate positive index.
*/
- public static final int OUT_OF_BOUNDS = Short.MAX_VALUE;
+ public static final int OUT_OF_BOUNDS = Integer.MAX_VALUE;
/**
* Use this to specify an indeterminate negative index.
*/
- public static final int OUT_OF_BOUNDS_NEGATIVE = Short.MIN_VALUE;
+ public static final int OUT_OF_BOUNDS_NEGATIVE = Integer.MIN_VALUE;
private static final String NO_VERSION_TAG = "";