summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl4
-rw-r--r--core/java/android/app/ActivityManager.java21
-rw-r--r--core/java/android/app/ActivityManagerNative.java6
-rw-r--r--core/java/android/app/ActivityOptions.java68
-rw-r--r--core/java/android/app/ActivityThread.java22
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java23
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/ApplicationThreadNative.java6
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java10
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java10
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/app/IApplicationThread.java2
-rw-r--r--core/java/android/app/IWallpaperManager.aidl6
-rw-r--r--core/java/android/app/Notification.java54
-rw-r--r--core/java/android/app/WallpaperManager.java43
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java4
-rw-r--r--core/java/android/content/ContentProvider.java22
-rw-r--r--core/java/android/content/pm/ActivityInfo.java10
-rw-r--r--core/java/android/content/pm/LauncherApps.java66
-rw-r--r--core/java/android/content/pm/PackageInstaller.java72
-rw-r--r--core/java/android/content/pm/PackageManager.java24
-rw-r--r--core/java/android/content/pm/PackageParser.java6
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java5
-rw-r--r--core/java/android/os/FileBridge.java18
-rw-r--r--core/java/android/os/Message.java16
-rw-r--r--core/java/android/os/Process.java10
-rw-r--r--core/java/android/provider/CallLog.java2
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java39
-rw-r--r--core/java/android/service/wallpaper/IWallpaperEngine.aidl2
-rw-r--r--core/java/android/service/wallpaper/IWallpaperService.aidl3
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java172
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java149
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java12
-rw-r--r--core/java/android/speech/tts/Voice.java2
-rw-r--r--core/java/android/transition/Transition.java18
-rw-r--r--core/java/android/transition/TransitionSet.java2
-rw-r--r--core/java/android/transition/Visibility.java16
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java146
-rw-r--r--core/java/android/view/IWindowManager.aidl3
-rw-r--r--core/java/android/view/IWindowSession.aidl5
-rw-r--r--core/java/android/view/View.java142
-rw-r--r--core/java/android/view/ViewGroup.java106
-rw-r--r--core/java/android/view/ViewRootImpl.java26
-rw-r--r--core/java/android/view/WindowInsets.java54
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java69
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl5
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl9
-rw-r--r--core/java/android/view/inputmethod/CursorAnchorInfo.java171
-rw-r--r--core/java/android/widget/AbsListView.java17
-rw-r--r--core/java/android/widget/DatePicker.java61
-rw-r--r--core/java/android/widget/DatePickerCalendarDelegate.java11
-rw-r--r--core/java/android/widget/DatePickerController.java1
-rw-r--r--core/java/android/widget/Editor.java105
53 files changed, 1485 insertions, 395 deletions
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 5f7a17d..27a03b6 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -54,6 +54,10 @@ interface IAccessibilityServiceConnection {
int action, in Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long threadId);
+ boolean computeClickPointInScreen(int accessibilityWindowId, long accessibilityNodeId,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ long threadId);
+
AccessibilityWindowInfo getWindow(int windowId);
List<AccessibilityWindowInfo> getWindows();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3e03893..9486a72 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2656,17 +2656,24 @@ public class ActivityManager {
/**
* Start an activity in this task. Brings the task to the foreground. If this task
- * is not currently active (that is, its id < 0), then the activity being started
- * needs to be started as a new task and the Intent's ComponentName must match the
- * base ComponenentName of the recent task entry. Otherwise, the activity being
- * started must <b>not</b> be launched as a new task -- not through explicit intent
- * flags nor implicitly as the singleTask or singleInstance launch modes.
+ * is not currently active (that is, its id < 0), then a new activity for the given
+ * Intent will be launched as the root of the task and the task brought to the
+ * foreground. Otherwise, if this task is currently active and the Intent does not specify
+ * an activity to launch in a new task, then a new activity for the given Intent will
+ * be launched on top of the task and the task brought to the foreground. If this
+ * task is currently active and the Intent specifies {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ * or would otherwise be launched in to a new task, then the activity not launched but
+ * this task be brought to the foreground and a new intent delivered to the top
+ * activity if appropriate.
*
- * <p>See {@link Activity#startActivity(android.content.Intent, android.os.Bundle)
- * Activity.startActivity} for more information.</p>
+ * <p>In other words, you generally want to use an Intent here that does not specify
+ * {@link Intent#FLAG_ACTIVITY_NEW_TASK} or {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT},
+ * and let the system do the right thing.</p>
*
* @param intent The Intent describing the new activity to be launched on the task.
* @param options Optional launch options.
+ *
+ * @see Activity#startActivity(android.content.Intent, android.os.Bundle)
*/
public void startActivity(Context context, Intent intent, Bundle options) {
ActivityThread thread = ActivityThread.currentActivityThread();
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1f7e450..394b183 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -509,8 +509,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case ACTIVITY_PAUSED_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- PersistableBundle persistentState = data.readPersistableBundle();
- activityPaused(token, persistentState);
+ activityPaused(token);
reply.writeNoException();
return true;
}
@@ -2829,13 +2828,12 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
- public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException
+ public void activityPaused(IBinder token) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
- data.writePersistableBundle(persistentState);
mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 9dd4605..213c7f6 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -84,13 +84,13 @@ public class ActivityOptions {
* Initial width of the animation.
* @hide
*/
- public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth";
+ public static final String KEY_ANIM_WIDTH = "android:animWidth";
/**
* Initial height of the animation.
* @hide
*/
- public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight";
+ public static final String KEY_ANIM_HEIGHT = "android:animHeight";
/**
* Callback for when animation is started.
@@ -140,8 +140,8 @@ public class ActivityOptions {
private Bitmap mThumbnail;
private int mStartX;
private int mStartY;
- private int mStartWidth;
- private int mStartHeight;
+ private int mWidth;
+ private int mHeight;
private IRemoteCallback mAnimationStartedListener;
private ResultReceiver mTransitionReceiver;
private boolean mIsReturning;
@@ -238,13 +238,13 @@ public class ActivityOptions {
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
* @param startX The x starting location of the new activity, relative to <var>source</var>.
* @param startY The y starting location of the activity, relative to <var>source</var>.
- * @param startWidth The initial width of the new activity.
- * @param startHeight The initial height of the new activity.
+ * @param width The initial width of the new activity.
+ * @param height The initial height of the new activity.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
*/
public static ActivityOptions makeScaleUpAnimation(View source,
- int startX, int startY, int startWidth, int startHeight) {
+ int startX, int startY, int width, int height) {
ActivityOptions opts = new ActivityOptions();
opts.mPackageName = source.getContext().getPackageName();
opts.mAnimationType = ANIM_SCALE_UP;
@@ -252,8 +252,8 @@ public class ActivityOptions {
source.getLocationOnScreen(pts);
opts.mStartX = pts[0] + startX;
opts.mStartY = pts[1] + startY;
- opts.mStartWidth = startWidth;
- opts.mStartHeight = startHeight;
+ opts.mWidth = width;
+ opts.mHeight = height;
return opts;
}
@@ -359,9 +359,10 @@ public class ActivityOptions {
* @hide
*/
public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source,
- Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
- return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY, listener,
- true);
+ Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
+ OnAnimationStartedListener listener) {
+ return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
+ targetWidth, targetHeight, listener, true);
}
/**
@@ -382,13 +383,15 @@ public class ActivityOptions {
* @hide
*/
public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
- Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
- return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY, listener,
- false);
+ Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
+ OnAnimationStartedListener listener) {
+ return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
+ targetWidth, targetHeight, listener, false);
}
private static ActivityOptions makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail,
- int startX, int startY, OnAnimationStartedListener listener, boolean scaleUp) {
+ int startX, int startY, int targetWidth, int targetHeight,
+ OnAnimationStartedListener listener, boolean scaleUp) {
ActivityOptions opts = new ActivityOptions();
opts.mPackageName = source.getContext().getPackageName();
opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_ASPECT_SCALE_UP :
@@ -398,6 +401,8 @@ public class ActivityOptions {
source.getLocationOnScreen(pts);
opts.mStartX = pts[0] + startX;
opts.mStartY = pts[1] + startY;
+ opts.mWidth = targetWidth;
+ opts.mHeight = targetHeight;
opts.setOnAnimationStartedListener(source.getHandler(), listener);
return opts;
}
@@ -515,11 +520,6 @@ public class ActivityOptions {
return opts;
}
- @Deprecated
- public static ActivityOptions makeLaunchTaskBehindAnimation() {
- return makeTaskLaunchBehind();
- }
-
/** @hide */
public boolean getLaunchTaskBehind() {
return mAnimationType == ANIM_LAUNCH_TASK_BEHIND;
@@ -543,8 +543,8 @@ public class ActivityOptions {
case ANIM_SCALE_UP:
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
- mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
- mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
+ mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
+ mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
break;
case ANIM_THUMBNAIL_SCALE_UP:
@@ -554,6 +554,8 @@ public class ActivityOptions {
mThumbnail = (Bitmap) opts.getParcelable(KEY_ANIM_THUMBNAIL);
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
+ mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
+ mHeight = opts.getInt(KEY_ANIM_HEIGHT, 0);
mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
opts.getBinder(KEY_ANIM_START_LISTENER));
break;
@@ -605,13 +607,13 @@ public class ActivityOptions {
}
/** @hide */
- public int getStartWidth() {
- return mStartWidth;
+ public int getWidth() {
+ return mWidth;
}
/** @hide */
- public int getStartHeight() {
- return mStartHeight;
+ public int getHeight() {
+ return mHeight;
}
/** @hide */
@@ -690,8 +692,8 @@ public class ActivityOptions {
case ANIM_SCALE_UP:
mStartX = otherOptions.mStartX;
mStartY = otherOptions.mStartY;
- mStartWidth = otherOptions.mStartWidth;
- mStartHeight = otherOptions.mStartHeight;
+ mWidth = otherOptions.mWidth;
+ mHeight = otherOptions.mHeight;
if (mAnimationStartedListener != null) {
try {
mAnimationStartedListener.sendResult(null);
@@ -707,6 +709,8 @@ public class ActivityOptions {
mThumbnail = otherOptions.mThumbnail;
mStartX = otherOptions.mStartX;
mStartY = otherOptions.mStartY;
+ mWidth = otherOptions.mWidth;
+ mHeight = otherOptions.mHeight;
if (mAnimationStartedListener != null) {
try {
mAnimationStartedListener.sendResult(null);
@@ -755,8 +759,8 @@ public class ActivityOptions {
case ANIM_SCALE_UP:
b.putInt(KEY_ANIM_START_X, mStartX);
b.putInt(KEY_ANIM_START_Y, mStartY);
- b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
- b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
+ b.putInt(KEY_ANIM_WIDTH, mWidth);
+ b.putInt(KEY_ANIM_HEIGHT, mHeight);
break;
case ANIM_THUMBNAIL_SCALE_UP:
case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -765,6 +769,8 @@ public class ActivityOptions {
b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
b.putInt(KEY_ANIM_START_X, mStartX);
b.putInt(KEY_ANIM_START_Y, mStartY);
+ b.putInt(KEY_ANIM_WIDTH, mWidth);
+ b.putInt(KEY_ANIM_HEIGHT, mHeight);
b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
!= null ? mAnimationStartedListener.asBinder() : null);
break;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4f2a3bc..3a39900 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -563,11 +563,11 @@ public final class ActivityThread {
}
public final void schedulePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges) {
+ boolean userLeaving, int configChanges, boolean dontReport) {
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
- (userLeaving ? 1 : 0),
+ (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
configChanges);
}
@@ -1283,13 +1283,15 @@ public final class ActivityThread {
} break;
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
- handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
+ handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
+ (msg.arg1&2) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY_FINISHING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
- handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
+ handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2,
+ (msg.arg1&1) != 0);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_ACTIVITY_SHOW:
@@ -3142,7 +3144,7 @@ public final class ActivityThread {
}
private void handlePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges) {
+ boolean userLeaving, int configChanges, boolean dontReport) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
@@ -3159,9 +3161,11 @@ public final class ActivityThread {
}
// Tell the activity manager we have paused.
- try {
- ActivityManagerNative.getDefault().activityPaused(token, r.persistentState);
- } catch (RemoteException ex) {
+ if (!dontReport) {
+ try {
+ ActivityManagerNative.getDefault().activityPaused(token);
+ } catch (RemoteException ex) {
+ }
}
mSomeActivitiesChanged = true;
}
@@ -4283,6 +4287,8 @@ public final class ActivityThread {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+ Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
+
/*
* Before spawning a new process, reset the time zone to be the system time zone.
* This needs to be done because the system time zone could have changed after the
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 9e80a4b..9f49194 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -205,6 +205,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
private boolean mIsStartingTransition;
private ArrayList<GhostViewListeners> mGhostViewListeners =
new ArrayList<GhostViewListeners>();
+ private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>();
public ActivityTransitionCoordinator(Window window,
ArrayList<String> allSharedElementNames,
@@ -580,6 +581,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
mWindow = null;
mSharedElements.clear();
mTransitioningViews.clear();
+ mOriginalAlphas.clear();
mResultReceiver = null;
mPendingTransition = null;
mListener = null;
@@ -589,10 +591,27 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
return getWindow().getTransitionBackgroundFadeDuration();
}
- protected static void setTransitionAlpha(ArrayList<View> views, float alpha) {
+ protected void hideViews(ArrayList<View> views) {
int count = views.size();
for (int i = 0; i < count; i++) {
- views.get(i).setTransitionAlpha(alpha);
+ View view = views.get(i);
+ if (!mOriginalAlphas.containsKey(view)) {
+ mOriginalAlphas.put(view, view.getAlpha());
+ }
+ view.setAlpha(0f);
+ view.setTransitionAlpha(0f);
+ }
+ }
+
+ protected void showViews(ArrayList<View> views) {
+ int count = views.size();
+ for (int i = 0; i < count; i++) {
+ View view = views.get(i);
+ Float alpha = mOriginalAlphas.remove(view);
+ if (alpha != null) {
+ view.setAlpha(alpha);
+ view.setTransitionAlpha(1f);
+ }
}
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9cd6d49..404268c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1693,7 +1693,7 @@ final class ApplicationPackageManager extends PackageManager {
if (dr == null) {
dr = itemInfo.loadDefaultIcon(this);
}
- return getUserBadgedDrawableForDensity(dr, new UserHandle(mContext.getUserId()), null, 0);
+ return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId()));
}
private Drawable getBadgedDrawable(Drawable drawable, Drawable badgeDrawable,
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 63e8707..0123e16 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -78,7 +78,8 @@ public abstract class ApplicationThreadNative extends Binder
boolean finished = data.readInt() != 0;
boolean userLeaving = data.readInt() != 0;
int configChanges = data.readInt();
- schedulePauseActivity(b, finished, userLeaving, configChanges);
+ boolean dontReport = data.readInt() != 0;
+ schedulePauseActivity(b, finished, userLeaving, configChanges, dontReport);
return true;
}
@@ -689,13 +690,14 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public final void schedulePauseActivity(IBinder token, boolean finished,
- boolean userLeaving, int configChanges) throws RemoteException {
+ boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(finished ? 1 : 0);
data.writeInt(userLeaving ? 1 :0);
data.writeInt(configChanges);
+ data.writeInt(dontReport ? 1 : 0);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index f432c49..f38c108 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -112,9 +112,9 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
protected void viewsReady(ArrayMap<String, View> sharedElements) {
super.viewsReady(sharedElements);
mIsReadyForTransition = true;
- setTransitionAlpha(mSharedElements, 0);
+ hideViews(mSharedElements);
if (getViewsTransition() != null) {
- setTransitionAlpha(mTransitioningViews, 0);
+ hideViews(mTransitioningViews);
}
if (mIsReturning) {
sendSharedElementDestination();
@@ -240,7 +240,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
if (!mIsCanceled) {
mIsCanceled = true;
if (getViewsTransition() == null || mIsViewsTransitionStarted) {
- setTransitionAlpha(mSharedElements, 1);
+ showViews(mSharedElements);
} else {
mTransitioningViews.addAll(mSharedElements);
}
@@ -300,7 +300,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
// Now start shared element transition
ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
mSharedElementNames);
- setTransitionAlpha(mSharedElements, 1);
+ showViews(mSharedElements);
scheduleSetSharedElementEnd(sharedElementSnapshots);
ArrayList<SharedElementOriginalState> originalImageViewState =
setSharedElementState(sharedElementState, sharedElementSnapshots);
@@ -411,7 +411,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
public void onTransitionStart(Transition transition) {
mEnterViewsTransition = transition;
- setTransitionAlpha(mTransitioningViews, 1);
+ showViews(mTransitioningViews);
super.onTransitionStart(transition);
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index a59a927..982bbc4 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -126,8 +126,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
}
public void resetViews() {
- setTransitionAlpha(mTransitioningViews, 1);
- setTransitionAlpha(mSharedElements, 1);
+ showViews(mTransitioningViews);
+ showViews(mSharedElements);
mIsHidden = true;
if (!mIsReturning && getDecor() != null) {
getDecor().suppressLayout(false);
@@ -187,7 +187,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private void hideSharedElements() {
moveSharedElementsFromOverlay();
if (!mIsHidden) {
- setTransitionAlpha(mSharedElements, 0);
+ hideViews(mSharedElements);
}
mSharedElementsHidden = true;
finishIfNecessary();
@@ -296,7 +296,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
transition.removeListener(this);
exitTransitionComplete();
if (mIsHidden) {
- setTransitionAlpha(mTransitioningViews, 1);
+ showViews(mTransitioningViews);
}
if (mSharedElementBundle != null) {
delayCancel();
@@ -323,7 +323,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
transition.removeListener(this);
sharedElementTransitionComplete();
if (mIsHidden) {
- setTransitionAlpha(mSharedElements, 1);
+ showViews(mSharedElements);
}
}
});
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 99428e8..9483680 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -111,7 +111,7 @@ public interface IActivityManager extends IInterface {
public void activityResumed(IBinder token) throws RemoteException;
public void activityIdle(IBinder token, Configuration config,
boolean stopProfiling) throws RemoteException;
- public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException;
+ public void activityPaused(IBinder token) throws RemoteException;
public void activityStopped(IBinder token, Bundle state,
PersistableBundle persistentState, CharSequence description) throws RemoteException;
public void activitySlept(IBinder token) throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index a7546d9..f53075c 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -49,7 +49,7 @@ import java.util.Map;
*/
public interface IApplicationThread extends IInterface {
void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving,
- int configChanges) throws RemoteException;
+ int configChanges, boolean dontReport) throws RemoteException;
void scheduleStopActivity(IBinder token, boolean showWindow,
int configChanges) throws RemoteException;
void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException;
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 181eb63..3b5900b 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -16,6 +16,7 @@
package android.app;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.app.IWallpaperManagerCallback;
@@ -73,6 +74,11 @@ interface IWallpaperManager {
int getHeightHint();
/**
+ * Sets extra padding that we would like the wallpaper to have outside of the display.
+ */
+ void setDisplayPadding(in Rect padding);
+
+ /**
* Returns the name of the wallpaper. Private API.
*/
String getName();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1083943..2476c4b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -545,8 +545,26 @@ public class Notification implements Parcelable
*/
public int visibility;
+ /**
+ * Notification visibility: Show this notification in its entirety on all lockscreens.
+ *
+ * {@see #visibility}
+ */
public static final int VISIBILITY_PUBLIC = 1;
+
+ /**
+ * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or
+ * private information on secure lockscreens.
+ *
+ * {@see #visibility}
+ */
public static final int VISIBILITY_PRIVATE = 0;
+
+ /**
+ * Notification visibility: Do not reveal any part of this notification on a secure lockscreen.
+ *
+ * {@see #visibility}
+ */
public static final int VISIBILITY_SECRET = -1;
/**
@@ -3386,8 +3404,16 @@ public class Notification implements Parcelable
*/
public static abstract class Style {
private CharSequence mBigContentTitle;
- private CharSequence mSummaryText = null;
- private boolean mSummaryTextSet = false;
+
+ /**
+ * @hide
+ */
+ protected CharSequence mSummaryText = null;
+
+ /**
+ * @hide
+ */
+ protected boolean mSummaryTextSet = false;
protected Builder mBuilder;
@@ -3679,6 +3705,11 @@ public class Notification implements Parcelable
* @see Notification#bigContentView
*/
public static class BigTextStyle extends Style {
+
+ private static final int MAX_LINES = 13;
+ private static final int LINES_CONSUMED_BY_ACTIONS = 3;
+ private static final int LINES_CONSUMED_BY_SUMMARY = 2;
+
private CharSequence mBigText;
public BigTextStyle() {
@@ -3745,6 +3776,7 @@ public class Notification implements Parcelable
contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
+ contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines());
contentView.setViewVisibility(R.id.text2, View.GONE);
applyTopPadding(contentView);
@@ -3756,6 +3788,24 @@ public class Notification implements Parcelable
return contentView;
}
+ private int calculateMaxLines() {
+ int lineCount = MAX_LINES;
+ boolean hasActions = mBuilder.mActions.size() > 0;
+ boolean hasSummary = (mSummaryTextSet ? mSummaryText : mBuilder.mSubText) != null;
+ if (hasActions) {
+ lineCount -= LINES_CONSUMED_BY_ACTIONS;
+ }
+ if (hasSummary) {
+ lineCount -= LINES_CONSUMED_BY_SUMMARY;
+ }
+
+ // If we have less top padding at the top, we can fit less lines.
+ if (!mBuilder.mHasThreeLines) {
+ lineCount--;
+ }
+ return lineCount;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 48ff5b6..8bfe6d3 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -951,6 +952,48 @@ public class WallpaperManager {
}
/**
+ * Specify extra padding that the wallpaper should have outside of the display.
+ * That is, the given padding supplies additional pixels the wallpaper should extend
+ * outside of the display itself.
+ * @param padding The number of pixels the wallpaper should extend beyond the display,
+ * on its left, top, right, and bottom sides.
+ * @hide
+ */
+ @SystemApi
+ public void setDisplayPadding(Rect padding) {
+ try {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ } else {
+ sGlobals.mService.setDisplayPadding(padding);
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
+ /**
+ * Apply a raw offset to the wallpaper window. Should only be used in
+ * combination with {@link #setDisplayPadding(android.graphics.Rect)} when you
+ * have ensured that the wallpaper will extend outside of the display area so that
+ * it can be moved without leaving part of the display uncovered.
+ * @param x The offset, in pixels, to apply to the left edge.
+ * @param y The offset, in pixels, to apply to the top edge.
+ * @hide
+ */
+ @SystemApi
+ public void setDisplayOffset(IBinder windowToken, int x, int y) {
+ try {
+ //Log.v(TAG, "Sending new wallpaper display offsets from app...");
+ WindowManagerGlobal.getWindowSession().setWallpaperDisplayOffset(
+ windowToken, x, y);
+ //Log.v(TAG, "...app returning after sending display offset!");
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
+ /**
* Set the position of the current wallpaper within any larger space, when
* that wallpaper is visible behind the given window. The X and Y offsets
* are floating point numbers ranging from 0 to 1, representing where the
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 112fc82..926a348 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -441,13 +441,13 @@ public class DevicePolicyManager {
* Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from a
* managed profile to its parent.
*/
- public static int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
+ public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
/**
* Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from the
* parent to its managed profile.
*/
- public static int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
+ public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
/**
* Return true if the given administrator component is currently
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index fde8b2e..2853c58 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -639,12 +639,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* @param authorities the semi-colon separated authorities of the ContentProvider.
*/
protected final void setAuthorities(String authorities) {
- if (authorities.indexOf(';') == -1) {
- mAuthority = authorities;
- mAuthorities = null;
- } else {
- mAuthority = null;
- mAuthorities = authorities.split(";");
+ if (authorities != null) {
+ if (authorities.indexOf(';') == -1) {
+ mAuthority = authorities;
+ mAuthorities = null;
+ } else {
+ mAuthority = null;
+ mAuthorities = authorities.split(";");
+ }
}
}
@@ -653,9 +655,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (mAuthority != null) {
return mAuthority.equals(authority);
}
- int length = mAuthorities.length;
- for (int i = 0; i < length; i++) {
- if (mAuthorities[i].equals(authority)) return true;
+ if (mAuthorities != null) {
+ int length = mAuthorities.length;
+ for (int i = 0; i < length; i++) {
+ if (mAuthorities[i].equals(authority)) return true;
+ }
}
return false;
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index dbf49c5..8d3126d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -255,16 +255,22 @@ public class ActivityInfo extends ComponentInfo
* Bit in {@link #flags}: If set, a task rooted at this activity will have its
* baseIntent replaced by the activity immediately above this. Each activity may further
* relinquish its identity to the activity above it using this flag. Set from the
- * android.R.attr#relinquishTaskIdentity attribute.
+ * {@link android.R.attr#relinquishTaskIdentity} attribute.
*/
public static final int FLAG_RELINQUISH_TASK_IDENTITY = 0x1000;
/**
* Bit in {@link #flags} indicating that tasks started with this activity are to be
* removed from the recent list of tasks when the last activity in the task is finished.
- * {@link android.R.attr#autoRemoveFromRecents}
+ * Corresponds to {@link android.R.attr#autoRemoveFromRecents}
*/
public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 0x2000;
/**
+ * Bit in {@link #flags} indicating that this activity can start is creation/resume
+ * while the previous activity is still pausing. Corresponds to
+ * {@link android.R.attr#resumeWhilePausing}
+ */
+ public static final int FLAG_RESUME_WHILE_PAUSING = 0x4000;
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
* android.R.attr#primaryUserOnly attribute.
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index f9370b3..d49bc50 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -278,21 +278,21 @@ public class LauncherApps {
/**
- * Adds a callback for changes to packages in current and managed profiles.
+ * Registers a callback for changes to packages in current and managed profiles.
*
- * @param callback The callback to add.
+ * @param callback The callback to register.
*/
- public void addCallback(Callback callback) {
- addCallback(callback, null);
+ public void registerCallback(Callback callback) {
+ registerCallback(callback, null);
}
/**
- * Adds a callback for changes to packages in current and managed profiles.
+ * Registers a callback for changes to packages in current and managed profiles.
*
- * @param callback The callback to add.
+ * @param callback The callback to register.
* @param handler that should be used to post callbacks on, may be null.
*/
- public void addCallback(Callback callback, Handler handler) {
+ public void registerCallback(Callback callback, Handler handler) {
synchronized (this) {
if (callback != null && !mCallbacks.contains(callback)) {
boolean addedFirstCallback = mCallbacks.size() == 0;
@@ -308,12 +308,12 @@ public class LauncherApps {
}
/**
- * Removes a callback that was previously added.
+ * Unregisters a callback that was previously registered.
*
- * @param callback The callback to remove.
- * @see #addCallback(Callback)
+ * @param callback The callback to unregister.
+ * @see #registerCallback(Callback)
*/
- public void removeCallback(Callback callback) {
+ public void unregisterCallback(Callback callback) {
synchronized (this) {
removeCallbackLocked(callback);
if (mCallbacks.size() == 0) {
@@ -500,44 +500,12 @@ public class LauncherApps {
}
}
- /** Remove after unbundled apps have migrated STOP SHIP */
- public static abstract class OnAppsChangedCallback extends Callback {
- }
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public void addOnAppsChangedCallback(OnAppsChangedCallback callback) {
- addCallback(callback, null);
- }
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public void addOnAppsChangedCallback(OnAppsChangedCallback callback, Handler handler) {
- addCallback(callback, handler);
- }
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public void removeOnAppsChangedCallback(OnAppsChangedCallback callback) {
- removeCallback(callback);
- }
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public void startActivityForProfile(ComponentName component, UserHandle user, Rect sourceBounds,
- Bundle opts) {
- startMainActivity(component, user, sourceBounds, opts);
- }
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public void showAppDetailsForProfile(ComponentName component, UserHandle user,
- Rect sourceBounds, Bundle opts) {
- startAppDetailsActivity(component, user, sourceBounds, opts);
- }
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
- return isPackageEnabled(packageName, user);
+ /** STOPSHIP remove when launcher 3 has been updated */
+ public void addCallback(Callback callback) {
+ registerCallback(callback);
}
-
- /** Remove after unbundled apps have migrated STOP SHIP */
- public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
- return isActivityEnabled(component, user);
+ /** STOPSHIP remove when launcher 3 has been updated */
+ public void removeCallback(Callback callback) {
+ unregisterCallback(callback);
}
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0a211cf..06d4c4a 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -285,6 +285,9 @@ public class PackageInstaller {
*
* @throws IOException if parameters were unsatisfiable, such as lack of
* disk space or unavailable media.
+ * @throws SecurityException when installation services are unavailable,
+ * such as when called from a restricted user.
+ * @throws IllegalArgumentException when {@link SessionParams} is invalid.
* @return positive, non-zero unique ID that represents the created session.
* This ID remains consistent across device reboots until the
* session is finalized. IDs are not reused during a given boot.
@@ -303,6 +306,11 @@ public class PackageInstaller {
/**
* Open an existing session to actively perform work. To succeed, the caller
* must be the owner of the install session.
+ *
+ * @throws IOException if parameters were unsatisfiable, such as lack of
+ * disk space or unavailable media.
+ * @throws SecurityException when the caller does not own the session, or
+ * the session is invalid.
*/
public @NonNull Session openSession(int sessionId) throws IOException {
try {
@@ -319,6 +327,9 @@ public class PackageInstaller {
* Update the icon representing the app being installed in a specific
* session. This should be roughly
* {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions.
+ *
+ * @throws SecurityException when the caller does not own the session, or
+ * the session is invalid.
*/
public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) {
try {
@@ -331,6 +342,9 @@ public class PackageInstaller {
/**
* Update the label representing the app being installed in a specific
* session.
+ *
+ * @throws SecurityException when the caller does not own the session, or
+ * the session is invalid.
*/
public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) {
try {
@@ -341,6 +355,15 @@ public class PackageInstaller {
}
}
+ /**
+ * Completely abandon the given session, destroying all staged data and
+ * rendering it invalid. Abandoned sessions will be reported to
+ * {@link SessionCallback} listeners as failures. This is equivalent to
+ * opening the session and calling {@link Session#abandon()}.
+ *
+ * @throws SecurityException when the caller does not own the session, or
+ * the session is invalid.
+ */
public void abandonSession(int sessionId) {
try {
mInstaller.abandonSession(sessionId);
@@ -350,7 +373,11 @@ public class PackageInstaller {
}
/**
- * Return details for a specific session.
+ * Return details for a specific session. No special permissions are
+ * required to retrieve these details.
+ *
+ * @return details for the requested session, or {@code null} if the session
+ * does not exist.
*/
public @Nullable SessionInfo getSessionInfo(int sessionId) {
try {
@@ -361,7 +388,7 @@ public class PackageInstaller {
}
/**
- * Return list of all active install sessions, regardless of the installer.
+ * Return list of all known install sessions, regardless of the installer.
*/
public @NonNull List<SessionInfo> getAllSessions() {
final ApplicationInfo info = mContext.getApplicationInfo();
@@ -379,7 +406,7 @@ public class PackageInstaller {
}
/**
- * Return list of all install sessions owned by the calling app.
+ * Return list of all known install sessions owned by the calling app.
*/
public @NonNull List<SessionInfo> getMySessions() {
try {
@@ -547,7 +574,8 @@ public class PackageInstaller {
}
/**
- * Register to watch for session lifecycle events.
+ * Register to watch for session lifecycle events. No special permissions
+ * are required to watch for these events.
*/
public void registerSessionCallback(@NonNull SessionCallback callback) {
registerSessionCallback(callback, new Handler());
@@ -560,7 +588,8 @@ public class PackageInstaller {
}
/**
- * Register to watch for session lifecycle events.
+ * Register to watch for session lifecycle events. No special permissions
+ * are required to watch for these events.
*
* @param handler to dispatch callback events through, otherwise uses
* calling thread.
@@ -593,7 +622,7 @@ public class PackageInstaller {
}
/**
- * Unregister an existing callback.
+ * Unregister a previously registered callback.
*/
public void unregisterSessionCallback(@NonNull SessionCallback callback) {
synchronized (mDelegates) {
@@ -686,6 +715,12 @@ public class PackageInstaller {
* start at the beginning of the file.
* @param lengthBytes total size of the file being written, used to
* preallocate the underlying disk space, or -1 if unknown.
+ * The system may clear various caches as needed to allocate
+ * this space.
+ * @throws IOException if trouble opening the file for writing, such as
+ * lack of disk space or unavailable media.
+ * @throws SecurityException if called after the session has been
+ * committed or abandoned.
*/
public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
long lengthBytes) throws IOException {
@@ -719,6 +754,9 @@ public class PackageInstaller {
* <p>
* This returns all names which have been previously written through
* {@link #openWrite(String, long, long)} as part of this session.
+ *
+ * @throws SecurityException if called after the session has been
+ * committed or abandoned.
*/
public @NonNull String[] getNames() throws IOException {
try {
@@ -738,6 +776,9 @@ public class PackageInstaller {
* through {@link #openWrite(String, long, long)} as part of this
* session. For example, this stream may be used to calculate a
* {@link MessageDigest} of a written APK before committing.
+ *
+ * @throws SecurityException if called after the session has been
+ * committed or abandoned.
*/
public @NonNull InputStream openRead(@NonNull String name) throws IOException {
try {
@@ -759,6 +800,9 @@ public class PackageInstaller {
* Once this method is called, no additional mutations may be performed
* on the session. If the device reboots before the session has been
* finalized, you may commit the session again.
+ *
+ * @throws SecurityException if streams opened through
+ * {@link #openWrite(String, long, long)} are still open.
*/
public void commit(@NonNull IntentSender statusReceiver) {
try {
@@ -783,7 +827,9 @@ public class PackageInstaller {
/**
* Completely abandon this session, destroying all staged data and
- * rendering it invalid.
+ * rendering it invalid. Abandoned sessions will be reported to
+ * {@link SessionCallback} listeners as failures. This is equivalent to
+ * opening the session and calling {@link Session#abandon()}.
*/
public void abandon() {
try {
@@ -937,6 +983,18 @@ public class PackageInstaller {
}
/** {@hide} */
+ public void setInstallFlagsInternal() {
+ installFlags |= PackageManager.INSTALL_INTERNAL;
+ installFlags &= ~PackageManager.INSTALL_EXTERNAL;
+ }
+
+ /** {@hide} */
+ public void setInstallFlagsExternal() {
+ installFlags |= PackageManager.INSTALL_EXTERNAL;
+ installFlags &= ~PackageManager.INSTALL_INTERNAL;
+ }
+
+ /** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e87adda..36d15a0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -201,12 +201,6 @@ public abstract class PackageManager {
public static final int MATCH_DEFAULT_ONLY = 0x00010000;
/**
- * Resolution and querying flag: do not resolve intents cross-profile.
- * @hide
- */
- public static final int NO_CROSS_PROFILE = 0x00020000;
-
- /**
* Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
* when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current
* profile will be skipped.
@@ -976,6 +970,14 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device includes at least one form of audio
+ * output, such as speakers, audio jack or streaming over bluetooth
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device is capable of communicating with
* other devices via Bluetooth.
*/
@@ -1546,6 +1548,15 @@ public abstract class PackageManager {
public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device has all of the inputs necessary to be considered a compatible game controller, or
+ * includes a compatible game controller in the box.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
+
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
@@ -2423,7 +2434,6 @@ public abstract class PackageManager {
* @see #MATCH_DEFAULT_ONLY
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
- * @see #NO_CROSS_PROFILE
* @hide
*/
public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6d40dcf..e0fd532 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3110,6 +3110,12 @@ public class PackageParser {
false)) {
a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
}
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_resumeWhilePausing,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+ }
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 7a49eb5..7390e2b 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -480,7 +480,7 @@ public class SoundTrigger {
int capturePreambleMs = in.readInt();
boolean triggerInData = in.readByte() == 1;
AudioFormat captureFormat = null;
- if (triggerInData) {
+ if (in.readByte() == 1) {
int sampleRate = in.readInt();
int encoding = in.readInt();
int channelMask = in.readInt();
@@ -508,7 +508,8 @@ public class SoundTrigger {
dest.writeInt(captureSession);
dest.writeInt(captureDelayMs);
dest.writeInt(capturePreambleMs);
- if (triggerInData && (captureFormat != null)) {
+ dest.writeByte((byte) (triggerInData ? 1 : 0));
+ if (captureFormat != null) {
dest.writeByte((byte)1);
dest.writeInt(captureFormat.getSampleRate());
dest.writeInt(captureFormat.getEncoding());
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 022a106..0acf24b 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -75,6 +75,13 @@ public class FileBridge extends Thread {
return mClosed;
}
+ public void forceClose() {
+ IoUtils.closeQuietly(mTarget);
+ IoUtils.closeQuietly(mServer);
+ IoUtils.closeQuietly(mClient);
+ mClosed = true;
+ }
+
public void setTargetFile(FileDescriptor target) {
mTarget = target;
}
@@ -89,7 +96,6 @@ public class FileBridge extends Thread {
try {
while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {
final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);
-
if (cmd == CMD_WRITE) {
// Shuttle data into local file
int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
@@ -118,15 +124,10 @@ public class FileBridge extends Thread {
}
}
- } catch (ErrnoException e) {
- Log.wtf(TAG, "Failed during bridge", e);
- } catch (IOException e) {
+ } catch (ErrnoException | IOException e) {
Log.wtf(TAG, "Failed during bridge", e);
} finally {
- IoUtils.closeQuietly(mTarget);
- IoUtils.closeQuietly(mServer);
- IoUtils.closeQuietly(mClient);
- mClosed = true;
+ forceClose();
}
}
@@ -151,6 +152,7 @@ public class FileBridge extends Thread {
writeCommandAndBlock(CMD_CLOSE, "close()");
} finally {
IoBridge.closeAndSignalBlockedThreads(mClient);
+ IoUtils.closeQuietly(mClientPfd);
}
}
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 1a5811c..b6b70cc 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -113,6 +113,8 @@ public final class Message implements Parcelable {
private static final int MAX_POOL_SIZE = 50;
+ private static boolean gCheckRecycle = true;
+
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
@@ -256,6 +258,13 @@ public final class Message implements Parcelable {
return m;
}
+ /** @hide */
+ public static void updateCheckRecycle(int targetSdkVersion) {
+ if (targetSdkVersion < Build.VERSION_CODES.L) {
+ gCheckRecycle = false;
+ }
+ }
+
/**
* Return a Message instance to the global pool.
* <p>
@@ -266,8 +275,11 @@ public final class Message implements Parcelable {
*/
public void recycle() {
if (isInUse()) {
- throw new IllegalStateException("This message cannot be recycled because it "
- + "is still in use.");
+ if (gCheckRecycle) {
+ throw new IllegalStateException("This message cannot be recycled because it "
+ + "is still in use.");
+ }
+ return;
}
recycleUnchecked();
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index c3ac012..b2ebc31 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -468,6 +468,7 @@ public class Process {
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi non-null the ABI this app should be started with.
+ * @param instructionSet null-ok the instruction set to use.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -482,11 +483,12 @@ public class Process {
int targetSdkVersion,
String seInfo,
String abi,
+ String instructionSet,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
- abi, zygoteArgs);
+ abi, instructionSet, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -589,6 +591,7 @@ public class Process {
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi the ABI the process should use.
+ * @param instructionSet null-ok the instruction set to use.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -601,6 +604,7 @@ public class Process {
int targetSdkVersion,
String seInfo,
String abi,
+ String instructionSet,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
@@ -660,6 +664,10 @@ public class Process {
argsForZygote.add("--seinfo=" + seInfo);
}
+ if (instructionSet != null) {
+ argsForZygote.add("--instruction-set=" + instructionSet);
+ }
+
argsForZygote.add(processClass);
if (extraArgs != null) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 5fa1cc9..a5e86d8 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -167,8 +167,6 @@ public class CallLog {
*/
public static final String FEATURES = "features";
- /** Call had no associated features (e.g. voice-only). */
- public static final int FEATURES_NONE = 0x0;
/** Call had video. */
public static final int FEATURES_VIDEO = 0x1;
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 4de5f41..8aa2689 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -468,19 +468,6 @@ public class AlwaysOnHotwordDetector {
}
/**
- * FIXME: Remove once the prebuilts are updated.
- *
- * @hide
- */
- @Deprecated
- public Intent createIntentToEnroll() {
- if (DBG) Slog.d(TAG, "createIntentToEnroll");
- synchronized (mLock) {
- return getManageIntentLocked(MANAGE_ACTION_ENROLL);
- }
- }
-
- /**
* Creates an intent to start the un-enrollment for the associated keyphrase.
* This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
* Starting re-enrollment is only valid if the keyphrase is already enrolled,
@@ -502,19 +489,6 @@ public class AlwaysOnHotwordDetector {
}
/**
- * FIXME: Remove once the prebuilts are updated.
- *
- * @hide
- */
- @Deprecated
- public Intent createIntentToUnEnroll() {
- if (DBG) Slog.d(TAG, "createIntentToUnEnroll");
- synchronized (mLock) {
- return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL);
- }
- }
-
- /**
* Creates an intent to start the re-enrollment for the associated keyphrase.
* This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
* Starting re-enrollment is only valid if the keyphrase is already enrolled,
@@ -535,19 +509,6 @@ public class AlwaysOnHotwordDetector {
}
}
- /**
- * FIXME: Remove once the prebuilts are updated.
- *
- * @hide
- */
- @Deprecated
- public Intent createIntentToReEnroll() {
- if (DBG) Slog.d(TAG, "createIntentToReEnroll");
- synchronized (mLock) {
- return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL);
- }
- }
-
private Intent getManageIntentLocked(int action) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("getManageIntent called on an invalid detector");
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
index faccde2..de527e9 100644
--- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -16,6 +16,7 @@
package android.service.wallpaper;
+import android.graphics.Rect;
import android.view.MotionEvent;
import android.os.Bundle;
@@ -24,6 +25,7 @@ import android.os.Bundle;
*/
oneway interface IWallpaperEngine {
void setDesiredSize(int width, int height);
+ void setDisplayPadding(in Rect padding);
void setVisibility(boolean visible);
void dispatchPointer(in MotionEvent event);
void dispatchWallpaperCommand(String action, int x, int y,
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
index bc7a1d7..5fd0157 100644
--- a/core/java/android/service/wallpaper/IWallpaperService.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -16,6 +16,7 @@
package android.service.wallpaper;
+import android.graphics.Rect;
import android.service.wallpaper.IWallpaperConnection;
/**
@@ -24,5 +25,5 @@ import android.service.wallpaper.IWallpaperConnection;
oneway interface IWallpaperService {
void attach(IWallpaperConnection connection,
IBinder windowToken, int windowType, boolean isPreview,
- int reqWidth, int reqHeight);
+ int reqWidth, int reqHeight, in Rect padding);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f3c26c8..26e9a30 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -16,6 +16,14 @@
package android.service.wallpaper;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewRootImpl;
+import android.view.WindowInsets;
+import com.android.internal.R;
import com.android.internal.os.HandlerCaller;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseSurfaceHolder;
@@ -56,6 +64,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+
/**
* A wallpaper service is responsible for showing a live wallpaper behind
* applications that would like to sit on top of it. This service object
@@ -90,7 +100,8 @@ public abstract class WallpaperService extends Service {
private static final int DO_ATTACH = 10;
private static final int DO_DETACH = 20;
private static final int DO_SET_DESIRED_SIZE = 30;
-
+ private static final int DO_SET_DISPLAY_PADDING = 40;
+
private static final int MSG_UPDATE_SURFACE = 10000;
private static final int MSG_VISIBILITY_CHANGED = 10010;
private static final int MSG_WALLPAPER_OFFSETS = 10020;
@@ -150,13 +161,23 @@ public abstract class WallpaperService extends Service {
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
int mCurWindowFlags = mWindowFlags;
int mCurWindowPrivateFlags = mWindowPrivateFlags;
+ TypedValue mOutsetBottom;
final Rect mVisibleInsets = new Rect();
final Rect mWinFrame = new Rect();
final Rect mOverscanInsets = new Rect();
final Rect mContentInsets = new Rect();
final Rect mStableInsets = new Rect();
+ final Rect mDispatchedOverscanInsets = new Rect();
+ final Rect mDispatchedContentInsets = new Rect();
+ final Rect mDispatchedStableInsets = new Rect();
+ final Rect mFinalSystemInsets = new Rect();
+ final Rect mFinalStableInsets = new Rect();
final Configuration mConfiguration = new Configuration();
-
+
+ private boolean mIsEmulator;
+ private boolean mIsCircularEmulator;
+ private boolean mWindowIsRound;
+
final WindowManager.LayoutParams mLayout
= new WindowManager.LayoutParams();
IWindowSession mSession;
@@ -406,7 +427,7 @@ public abstract class WallpaperService extends Service {
*/
public void onCreate(SurfaceHolder surfaceHolder) {
}
-
+
/**
* Called right before the engine is going away. After this the
* surface will be destroyed and this Engine object is no longer
@@ -414,7 +435,7 @@ public abstract class WallpaperService extends Service {
*/
public void onDestroy() {
}
-
+
/**
* Called to inform you of the wallpaper becoming visible or
* hidden. <em>It is very important that a wallpaper only use
@@ -422,7 +443,17 @@ public abstract class WallpaperService extends Service {
*/
public void onVisibilityChanged(boolean visible) {
}
-
+
+ /**
+ * Called with the current insets that are in effect for the wallpaper.
+ * This gives you the part of the overall wallpaper surface that will
+ * generally be visible to the user (ignoring position offsets applied to it).
+ *
+ * @param insets Insets to apply.
+ */
+ public void onApplyWindowInsets(WindowInsets insets) {
+ }
+
/**
* Called as the user performs touch-screen interaction with the
* window that is currently showing this wallpaper. Note that the
@@ -432,7 +463,7 @@ public abstract class WallpaperService extends Service {
*/
public void onTouchEvent(MotionEvent event) {
}
-
+
/**
* Called to inform you of the wallpaper's offsets changing
* within its contain, corresponding to the container's
@@ -443,7 +474,7 @@ public abstract class WallpaperService extends Service {
float xOffsetStep, float yOffsetStep,
int xPixelOffset, int yPixelOffset) {
}
-
+
/**
* Process a command that was sent to the wallpaper with
* {@link WallpaperManager#sendWallpaperCommand}.
@@ -465,14 +496,14 @@ public abstract class WallpaperService extends Service {
Bundle extras, boolean resultRequested) {
return null;
}
-
+
/**
* Called when an application has changed the desired virtual size of
* the wallpaper.
*/
public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
}
-
+
/**
* Convenience for {@link SurfaceHolder.Callback#surfaceChanged
* SurfaceHolder.Callback.surfaceChanged()}.
@@ -561,16 +592,20 @@ public abstract class WallpaperService extends Service {
if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface: destroyed");
}
-
+
+ boolean fixedSize = false;
int myWidth = mSurfaceHolder.getRequestedWidth();
if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.MATCH_PARENT;
+ else fixedSize = true;
int myHeight = mSurfaceHolder.getRequestedHeight();
if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.MATCH_PARENT;
-
+ else fixedSize = true;
+
final boolean creating = !mCreated;
final boolean surfaceCreating = !mSurfaceCreated;
final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+ boolean insetsChanged = !mCreated;
final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
final boolean flagsChanged = mCurWindowFlags != mWindowFlags ||
mCurWindowPrivateFlags != mWindowPrivateFlags;
@@ -607,6 +642,32 @@ public abstract class WallpaperService extends Service {
mLayout.token = mWindowToken;
if (!mCreated) {
+ // Retrieve watch round and outset info
+ final WindowManager windowService = (WindowManager)getSystemService(
+ Context.WINDOW_SERVICE);
+ TypedArray windowStyle = obtainStyledAttributes(
+ com.android.internal.R.styleable.Window);
+ final Display display = windowService.getDefaultDisplay();
+ final boolean shouldUseBottomOutset =
+ display.getDisplayId() == Display.DEFAULT_DISPLAY;
+ if (shouldUseBottomOutset && windowStyle.hasValue(
+ R.styleable.Window_windowOutsetBottom)) {
+ if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+ windowStyle.getValue(R.styleable.Window_windowOutsetBottom,
+ mOutsetBottom);
+ } else {
+ mOutsetBottom = null;
+ }
+ mWindowIsRound = getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound);
+ windowStyle.recycle();
+
+ // detect emulator
+ mIsEmulator = Build.HARDWARE.contains("goldfish");
+ mIsCircularEmulator = SystemProperties.getBoolean(
+ ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
+
+ // Add window
mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
mLayout.setTitle(WallpaperService.this.getClass().getName());
@@ -627,6 +688,11 @@ public abstract class WallpaperService extends Service {
mSurfaceHolder.mSurfaceLock.lock();
mDrawingAllowed = true;
+ if (!fixedSize) {
+ mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding);
+ } else {
+ mLayout.surfaceInsets.set(0, 0, 0, 0);
+ }
final int relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
@@ -636,16 +702,39 @@ public abstract class WallpaperService extends Service {
+ ", frame=" + mWinFrame);
int w = mWinFrame.width();
+ int h = mWinFrame.height();
+
+ if (!fixedSize) {
+ final Rect padding = mIWallpaperEngine.mDisplayPadding;
+ w += padding.left + padding.right;
+ h += padding.top + padding.bottom;
+ mOverscanInsets.left += padding.left;
+ mOverscanInsets.top += padding.top;
+ mOverscanInsets.right += padding.right;
+ mOverscanInsets.bottom += padding.bottom;
+ mContentInsets.left += padding.left;
+ mContentInsets.top += padding.top;
+ mContentInsets.right += padding.right;
+ mContentInsets.bottom += padding.bottom;
+ mStableInsets.left += padding.left;
+ mStableInsets.top += padding.top;
+ mStableInsets.right += padding.right;
+ mStableInsets.bottom += padding.bottom;
+ }
+
if (mCurWidth != w) {
sizeChanged = true;
mCurWidth = w;
}
- int h = mWinFrame.height();
if (mCurHeight != h) {
sizeChanged = true;
mCurHeight = h;
}
+ insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets);
+ insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
+ insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
+
mSurfaceHolder.setSurfaceFrameSize(w, h);
mSurfaceHolder.mSurfaceLock.unlock();
@@ -702,6 +791,25 @@ public abstract class WallpaperService extends Service {
}
}
+ if (insetsChanged) {
+ mDispatchedOverscanInsets.set(mOverscanInsets);
+ mDispatchedContentInsets.set(mContentInsets);
+ mDispatchedStableInsets.set(mStableInsets);
+ final boolean isRound = (mIsEmulator && mIsCircularEmulator)
+ || mWindowIsRound;
+ mFinalSystemInsets.set(mDispatchedOverscanInsets);
+ mFinalStableInsets.set(mDispatchedStableInsets);
+ if (mOutsetBottom != null) {
+ final DisplayMetrics metrics = getResources().getDisplayMetrics();
+ mFinalSystemInsets.bottom =
+ ( (int) mOutsetBottom.getDimension(metrics) )
+ + mIWallpaperEngine.mDisplayPadding.bottom;
+ }
+ WindowInsets insets = new WindowInsets(mFinalSystemInsets,
+ null, mFinalStableInsets, isRound);
+ onApplyWindowInsets(insets);
+ }
+
if (redrawNeeded) {
onSurfaceRedrawNeeded(mSurfaceHolder);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
@@ -781,7 +889,7 @@ public abstract class WallpaperService extends Service {
mReportedVisible = false;
updateSurface(false, false, false);
}
-
+
void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
if (!mDestroyed) {
if (DEBUG) Log.v(TAG, "onDesiredSizeChanged("
@@ -792,14 +900,24 @@ public abstract class WallpaperService extends Service {
doOffsetsChanged(true);
}
}
-
+
+ void doDisplayPaddingChanged(Rect padding) {
+ if (!mDestroyed) {
+ if (DEBUG) Log.v(TAG, "onDisplayPaddingChanged(" + padding + "): " + this);
+ if (!mIWallpaperEngine.mDisplayPadding.equals(padding)) {
+ mIWallpaperEngine.mDisplayPadding.set(padding);
+ updateSurface(true, false, false);
+ }
+ }
+ }
+
void doVisibilityChanged(boolean visible) {
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
}
}
-
+
void reportVisibility() {
if (!mDestroyed) {
boolean visible = mVisible && mScreenOn;
@@ -956,12 +1074,13 @@ public abstract class WallpaperService extends Service {
boolean mShownReported;
int mReqWidth;
int mReqHeight;
-
+ final Rect mDisplayPadding = new Rect();
+
Engine mEngine;
-
+
IWallpaperEngineWrapper(WallpaperService context,
IWallpaperConnection conn, IBinder windowToken,
- int windowType, boolean isPreview, int reqWidth, int reqHeight) {
+ int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) {
mCaller = new HandlerCaller(context, context.getMainLooper(), this, true);
mConnection = conn;
mWindowToken = windowToken;
@@ -969,16 +1088,22 @@ public abstract class WallpaperService extends Service {
mIsPreview = isPreview;
mReqWidth = reqWidth;
mReqHeight = reqHeight;
+ mDisplayPadding.set(padding);
Message msg = mCaller.obtainMessage(DO_ATTACH);
mCaller.sendMessage(msg);
}
-
+
public void setDesiredSize(int width, int height) {
Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height);
mCaller.sendMessage(msg);
}
-
+
+ public void setDisplayPadding(Rect padding) {
+ Message msg = mCaller.obtainMessageO(DO_SET_DISPLAY_PADDING, padding);
+ mCaller.sendMessage(msg);
+ }
+
public void setVisibility(boolean visible) {
Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
visible ? 1 : 0);
@@ -1041,6 +1166,9 @@ public abstract class WallpaperService extends Service {
mEngine.doDesiredSizeChanged(message.arg1, message.arg2);
return;
}
+ case DO_SET_DISPLAY_PADDING: {
+ mEngine.doDisplayPaddingChanged((Rect) message.obj);
+ }
case MSG_UPDATE_SURFACE:
mEngine.updateSurface(true, false, false);
break;
@@ -1102,9 +1230,9 @@ public abstract class WallpaperService extends Service {
@Override
public void attach(IWallpaperConnection conn, IBinder windowToken,
- int windowType, boolean isPreview, int reqWidth, int reqHeight) {
+ int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) {
new IWallpaperEngineWrapper(mTarget, conn, windowToken,
- windowType, isPreview, reqWidth, reqHeight);
+ windowType, isPreview, reqWidth, reqHeight, padding);
}
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 7245975..a4b6e92 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -578,7 +578,7 @@ public class TextToSpeech {
*
* @deprecated Starting from API level 20, to select network synthesis, call
* ({@link TextToSpeech#getVoices()}, find a suitable network voice
- * ({@link Voice#getRequiresNetworkConnection()}) and pass it
+ * ({@link Voice#isNetworkConnectionRequired()}) and pass it
* to {@link TextToSpeech#setVoice(Voice)}).
*/
@Deprecated
@@ -596,7 +596,7 @@ public class TextToSpeech {
* @deprecated Starting from API level 20, to select embedded synthesis, call
* ({@link TextToSpeech#getVoices()}, find a suitable embedded voice
- * ({@link Voice#getRequiresNetworkConnection()}) and pass it
+ * ({@link Voice#isNetworkConnectionRequired()}) and pass it
* to {@link TextToSpeech#setVoice(Voice)}).
*/
@Deprecated
@@ -957,20 +957,18 @@ public class TextToSpeech {
*
* @param text
* The string of text. Example: <code>"south_south_east"</code>
- * @param filename
- * The full path to the sound file (for example:
- * "/sdcard/mysounds/hello.wav")
+ * @param file
+ * File object pointing to the sound file.
*
* @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
*/
- public int addSpeech(CharSequence text, String filename) {
+ public int addSpeech(CharSequence text, File file) {
synchronized (mStartLock) {
- mUtterances.put(text, Uri.parse(filename));
+ mUtterances.put(text, Uri.fromFile(file));
return SUCCESS;
}
}
-
/**
* Adds a mapping between a string of text and a sound resource in a
* package. Use this to add custom earcons.
@@ -1017,7 +1015,11 @@ public class TextToSpeech {
* "/sdcard/mysounds/tick.wav")
*
* @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ *
+ * @deprecated As of API level 20, replaced by
+ * {@link #addEarcon(String, File)}.
*/
+ @Deprecated
public int addEarcon(String earcon, String filename) {
synchronized(mStartLock) {
mEarcons.put(earcon, Uri.parse(filename));
@@ -1025,6 +1027,27 @@ public class TextToSpeech {
}
}
+ /**
+ * Adds a mapping between a string of text and a sound file.
+ * Use this to add custom earcons.
+ *
+ * @see #playEarcon(String, int, HashMap)
+ *
+ * @param earcon
+ * The name of the earcon.
+ * Example: <code>"[tick]"</code>
+ * @param file
+ * File object pointing to the sound file.
+ *
+ * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ */
+ public int addEarcon(String earcon, File file) {
+ synchronized(mStartLock) {
+ mEarcons.put(earcon, Uri.fromFile(file));
+ return SUCCESS;
+ }
+ }
+
private Uri makeResourceUri(String packageName, int resourceId) {
return new Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
@@ -1061,7 +1084,7 @@ public class TextToSpeech {
*/
public int speak(final CharSequence text,
final int queueMode,
- final HashMap<String, String> params,
+ final Bundle params,
final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
@@ -1103,11 +1126,11 @@ public class TextToSpeech {
*
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
* @deprecated As of API level 20, replaced by
- * {@link #speak(CharSequence, int, HashMap, String)}.
+ * {@link #speak(CharSequence, int, Bundle, String)}.
*/
@Deprecated
public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
- return speak(text, queueMode, params,
+ return speak(text, queueMode, convertParamsHashMaptoBundle(params),
params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
}
@@ -1135,7 +1158,7 @@ public class TextToSpeech {
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
*/
public int playEarcon(final String earcon, final int queueMode,
- final HashMap<String, String> params, final String utteranceId) {
+ final Bundle params, final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
public Integer run(ITextToSpeechService service) throws RemoteException {
@@ -1173,12 +1196,12 @@ public class TextToSpeech {
*
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
* @deprecated As of API level 20, replaced by
- * {@link #playEarcon(String, int, HashMap, String)}.
+ * {@link #playEarcon(String, int, Bundle, String)}.
*/
@Deprecated
public int playEarcon(final String earcon, final int queueMode,
final HashMap<String, String> params) {
- return playEarcon(earcon, queueMode, params,
+ return playEarcon(earcon, queueMode, convertParamsHashMaptoBundle(params),
params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
}
@@ -1757,22 +1780,20 @@ public class TextToSpeech {
* must be prefixed by the name of the engine they are intended for. For example
* the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
* engine named "com.svox.pico" if it is being used.
- * @param filename Absolute file filename to write the generated audio data to.It should be
- * something like "/sdcard/myappsounds/mysound.wav".
+ * @param file File to write the generated audio data to.
* @param utteranceId An unique identifier for this request.
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
*/
- public int synthesizeToFile(final CharSequence text, final HashMap<String, String> params,
- final String filename, final String utteranceId) {
+ public int synthesizeToFile(final CharSequence text, final Bundle params,
+ final File file, final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
public Integer run(ITextToSpeechService service) throws RemoteException {
ParcelFileDescriptor fileDescriptor;
int returnValue;
try {
- File file = new File(filename);
if(file.exists() && !file.canWrite()) {
- Log.e(TAG, "Can't write to " + filename);
+ Log.e(TAG, "Can't write to " + file);
return ERROR;
}
fileDescriptor = ParcelFileDescriptor.open(file,
@@ -1784,10 +1805,10 @@ public class TextToSpeech {
fileDescriptor.close();
return returnValue;
} catch (FileNotFoundException e) {
- Log.e(TAG, "Opening file " + filename + " failed", e);
+ Log.e(TAG, "Opening file " + file + " failed", e);
return ERROR;
} catch (IOException e) {
- Log.e(TAG, "Closing file " + filename + " failed", e);
+ Log.e(TAG, "Closing file " + file + " failed", e);
return ERROR;
}
}
@@ -1817,16 +1838,18 @@ public class TextToSpeech {
*
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
* @deprecated As of API level 20, replaced by
- * {@link #synthesizeToFile(CharSequence, HashMap, String, String)}.
+ * {@link #synthesizeToFile(CharSequence, Bundle, File, String)}.
*/
+ @Deprecated
public int synthesizeToFile(final String text, final HashMap<String, String> params,
final String filename) {
- return synthesizeToFile(text, params, filename, params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+ return synthesizeToFile(text, convertParamsHashMaptoBundle(params),
+ new File(filename), params.get(Engine.KEY_PARAM_UTTERANCE_ID));
}
- private Bundle getParams(HashMap<String, String> params) {
+ private Bundle convertParamsHashMaptoBundle(HashMap<String, String> params) {
if (params != null && !params.isEmpty()) {
- Bundle bundle = new Bundle(mParams);
+ Bundle bundle = new Bundle();
copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
copyIntParam(bundle, params, Engine.KEY_PARAM_SESSION_ID);
copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
@@ -1852,11 +1875,85 @@ public class TextToSpeech {
}
return bundle;
+ }
+ return null;
+ }
+
+ private Bundle getParams(Bundle params) {
+ if (params != null && !params.isEmpty()) {
+ Bundle bundle = new Bundle(mParams);
+ bundle.putAll(params);
+
+ verifyIntegerBundleParam(bundle, Engine.KEY_PARAM_STREAM);
+ verifyIntegerBundleParam(bundle, Engine.KEY_PARAM_SESSION_ID);
+ verifyStringBundleParam(bundle, Engine.KEY_PARAM_UTTERANCE_ID);
+ verifyFloatBundleParam(bundle, Engine.KEY_PARAM_VOLUME);
+ verifyFloatBundleParam(bundle, Engine.KEY_PARAM_PAN);
+
+ // Copy feature strings defined by the framework.
+ verifyBooleanBundleParam(bundle, Engine.KEY_FEATURE_NETWORK_SYNTHESIS);
+ verifyBooleanBundleParam(bundle, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS);
+ verifyIntegerBundleParam(bundle, Engine.KEY_FEATURE_NETWORK_TIMEOUT_MS);
+ verifyIntegerBundleParam(bundle, Engine.KEY_FEATURE_NETWORK_RETRIES_COUNT);
+
+ return bundle;
} else {
return mParams;
}
}
+ private static boolean verifyIntegerBundleParam(Bundle bundle, String key) {
+ if (bundle.containsKey(key)) {
+ if (!(bundle.get(key) instanceof Integer ||
+ bundle.get(key) instanceof Long)) {
+ bundle.remove(key);
+ Log.w(TAG, "Synthesis request paramter " + key + " containst value "
+ + " with invalid type. Should be an Integer or a Long");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean verifyStringBundleParam(Bundle bundle, String key) {
+ if (bundle.containsKey(key)) {
+ if (!(bundle.get(key) instanceof String)) {
+ bundle.remove(key);
+ Log.w(TAG, "Synthesis request paramter " + key + " containst value "
+ + " with invalid type. Should be a String");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean verifyBooleanBundleParam(Bundle bundle, String key) {
+ if (bundle.containsKey(key)) {
+ if (!(bundle.get(key) instanceof Boolean ||
+ bundle.get(key) instanceof String)) {
+ bundle.remove(key);
+ Log.w(TAG, "Synthesis request paramter " + key + " containst value "
+ + " with invalid type. Should be a Boolean or String");
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ private static boolean verifyFloatBundleParam(Bundle bundle, String key) {
+ if (bundle.containsKey(key)) {
+ if (!(bundle.get(key) instanceof Float ||
+ bundle.get(key) instanceof Double)) {
+ bundle.remove(key);
+ Log.w(TAG, "Synthesis request paramter " + key + " containst value "
+ + " with invalid type. Should be a Float or a Double");
+ return false;
+ }
+ }
+ return true;
+ }
+
private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
String value = params.get(key);
if (value != null) {
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 4fea109..d00a433 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -84,7 +84,7 @@ import java.util.Set;
* the following methods:
* <ul>
* <li>{@link #onGetVoices()}</li>
- * <li>{@link #isValidVoiceName(String)}</li>
+ * <li>{@link #onIsValidVoiceName(String)}</li>
* <li>{@link #onLoadVoice(String)}</li>
* <li>{@link #onGetDefaultVoiceNameFor(String, String, String)}</li>
* </ul>
@@ -278,7 +278,7 @@ public abstract class TextToSpeechService extends Service {
*
* @return A list of voices supported.
*/
- protected List<Voice> onGetVoices() {
+ public List<Voice> onGetVoices() {
// Enumerate all locales and check if they are available
ArrayList<Voice> voices = new ArrayList<Voice>();
for (Locale locale : Locale.getAvailableLocales()) {
@@ -335,7 +335,7 @@ public abstract class TextToSpeechService extends Service {
}
Locale properLocale = TtsEngines.normalizeTTSLocale(iso3Locale);
String voiceName = properLocale.toLanguageTag();
- if (isValidVoiceName(voiceName) == TextToSpeech.SUCCESS) {
+ if (onIsValidVoiceName(voiceName) == TextToSpeech.SUCCESS) {
return voiceName;
} else {
return null;
@@ -357,7 +357,7 @@ public abstract class TextToSpeechService extends Service {
* @param voiceName Name of the voice.
* @return {@link TextToSpeech#ERROR} or {@link TextToSpeech#SUCCESS}.
*/
- protected int onLoadVoice(String voiceName) {
+ public int onLoadVoice(String voiceName) {
Locale locale = Locale.forLanguageTag(voiceName);
if (locale == null) {
return TextToSpeech.ERROR;
@@ -388,7 +388,7 @@ public abstract class TextToSpeechService extends Service {
* @param voiceName Name of the voice.
* @return {@link TextToSpeech#ERROR} or {@link TextToSpeech#SUCCESS}.
*/
- protected int isValidVoiceName(String voiceName) {
+ public int onIsValidVoiceName(String voiceName) {
Locale locale = Locale.forLanguageTag(voiceName);
if (locale == null) {
return TextToSpeech.ERROR;
@@ -1275,7 +1275,7 @@ public abstract class TextToSpeechService extends Service {
if (!checkNonNull(voiceName)) {
return TextToSpeech.ERROR;
}
- int retVal = isValidVoiceName(voiceName);
+ int retVal = onIsValidVoiceName(voiceName);
if (retVal == TextToSpeech.SUCCESS) {
SpeechItem item = new LoadVoiceItem(caller, Binder.getCallingUid(),
diff --git a/core/java/android/speech/tts/Voice.java b/core/java/android/speech/tts/Voice.java
index a97141c..a1fa51d 100644
--- a/core/java/android/speech/tts/Voice.java
+++ b/core/java/android/speech/tts/Voice.java
@@ -162,7 +162,7 @@ public class Voice implements Parcelable {
/**
* @return Does the Voice require a network connection to work.
*/
- public boolean getRequiresNetworkConnection() {
+ public boolean isNetworkConnectionRequired() {
return mRequiresNetworkConnection;
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0d1b568..40bb6ec 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1417,9 +1417,9 @@ public abstract class Transition implements Cloneable {
}
capturePropagationValues(values);
if (start) {
- addViewValues(mStartValues, view, values);
+ addViewValues(mStartValues, view, values, true);
} else {
- addViewValues(mEndValues, view, values);
+ addViewValues(mEndValues, view, values, true);
}
}
}
@@ -1460,7 +1460,7 @@ public abstract class Transition implements Cloneable {
}
static void addViewValues(TransitionValuesMaps transitionValuesMaps,
- View view, TransitionValues transitionValues) {
+ View view, TransitionValues transitionValues, boolean setTransientState) {
transitionValuesMaps.viewValues.put(view, transitionValues);
int id = view.getId();
if (id >= 0) {
@@ -1489,11 +1489,15 @@ public abstract class Transition implements Cloneable {
// Duplicate item IDs: cannot match by item ID.
View alreadyMatched = transitionValuesMaps.itemIdValues.get(itemId);
if (alreadyMatched != null) {
- alreadyMatched.setHasTransientState(false);
+ if (setTransientState) {
+ alreadyMatched.setHasTransientState(false);
+ }
transitionValuesMaps.itemIdValues.put(itemId, null);
}
} else {
- view.setHasTransientState(true);
+ if (setTransientState) {
+ view.setHasTransientState(true);
+ }
transitionValuesMaps.itemIdValues.put(itemId, view);
}
}
@@ -1560,9 +1564,9 @@ public abstract class Transition implements Cloneable {
}
capturePropagationValues(values);
if (start) {
- addViewValues(mStartValues, view, values);
+ addViewValues(mStartValues, view, values, true);
} else {
- addViewValues(mEndValues, view, values);
+ addViewValues(mEndValues, view, values, true);
}
}
if (view instanceof ViewGroup) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index f6499ae..56db674 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -408,7 +408,7 @@ public class TransitionSet extends Transition {
for (int i = 0; i < numValues; i++) {
View view = values.viewValues.keyAt(i);
if (isValidTarget(view)) {
- addViewValues(included, view, values.viewValues.valueAt(i));
+ addViewValues(included, view, values.viewValues.valueAt(i), false);
}
}
return included;
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 0b02552..d648ca6 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -358,12 +358,16 @@ public abstract class Visibility extends Transition {
overlayView = startView;
} else if (startView.getParent() instanceof View) {
View startParent = (View) startView.getParent();
- if (!isValidTarget(startParent)) {
- if (startView.isAttachedToWindow()) {
- overlayView = copyViewImage(startView);
- } else {
- overlayView = startView;
- }
+ VisibilityInfo parentVisibilityInfo = null;
+ TransitionValues endParentValues = getMatchedTransitionValues(startParent,
+ true);
+ if (endParentValues != null) {
+ TransitionValues startParentValues = getTransitionValues(startParent, true);
+ parentVisibilityInfo =
+ getVisibilityChangeInfo(startParentValues, endParentValues);
+ }
+ if (parentVisibilityInfo == null || !parentVisibilityInfo.visibilityChange) {
+ overlayView = copyViewImage(startView);
} else if (startParent.getParent() == null) {
int id = startParent.getId();
if (id != View.NO_ID && sceneRoot.findViewById(id) != null
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index a10dda3..a283b91 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -19,7 +19,6 @@ package android.view;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -101,7 +100,7 @@ final class AccessibilityInteractionController {
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
- message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+ message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID;
message.arg1 = flags;
SomeArgs args = SomeArgs.obtain();
@@ -176,7 +175,7 @@ final class AccessibilityInteractionController {
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
- message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID;
+ message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID;
message.arg1 = flags;
message.arg2 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
@@ -261,7 +260,7 @@ final class AccessibilityInteractionController {
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
- message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
+ message.what = PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT;
message.arg1 = flags;
SomeArgs args = SomeArgs.obtain();
@@ -637,6 +636,95 @@ final class AccessibilityInteractionController {
}
}
+ public void computeClickPointInScreenClientThread(long accessibilityNodeId,
+ Region interactiveRegion, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+ long interrogatingTid, MagnificationSpec spec) {
+ Message message = mHandler.obtainMessage();
+ message.what = PrivateHandler.MSG_COMPUTE_CLICK_POINT_IN_SCREEN;
+
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+ args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
+ args.argi3 = interactionId;
+ args.arg1 = callback;
+ args.arg2 = spec;
+ args.arg3 = interactiveRegion;
+
+ message.obj = args;
+
+ // If the interrogation is performed by the same thread as the main UI
+ // thread in this process, set the message as a static reference so
+ // after this call completes the same thread but in the interrogating
+ // client can handle the message to generate the result.
+ if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
+ AccessibilityInteractionClient.getInstanceForThread(
+ interrogatingTid).setSameThreadMessage(message);
+ } else {
+ mHandler.sendMessage(message);
+ }
+ }
+
+ private void computeClickPointInScreenUiThread(Message message) {
+ SomeArgs args = (SomeArgs) message.obj;
+ final int accessibilityViewId = args.argi1;
+ final int virtualDescendantId = args.argi2;
+ final int interactionId = args.argi3;
+ final IAccessibilityInteractionConnectionCallback callback =
+ (IAccessibilityInteractionConnectionCallback) args.arg1;
+ final MagnificationSpec spec = (MagnificationSpec) args.arg2;
+ final Region interactiveRegion = (Region) args.arg3;
+ args.recycle();
+
+ boolean succeeded = false;
+ Point point = mTempPoint;
+ try {
+ if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+ return;
+ }
+ View target = null;
+ if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ target = findViewByAccessibilityId(accessibilityViewId);
+ } else {
+ target = mViewRootImpl.mView;
+ }
+ if (target != null && isShown(target)) {
+ AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
+ if (provider != null) {
+ // For virtual views just use the center of the bounds in screen.
+ AccessibilityNodeInfo node = null;
+ if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ node = provider.createAccessibilityNodeInfo(virtualDescendantId);
+ } else {
+ node = provider.createAccessibilityNodeInfo(
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+ }
+ if (node != null) {
+ succeeded = true;
+ Rect boundsInScreen = mTempRect;
+ node.getBoundsInScreen(boundsInScreen);
+ point.set(boundsInScreen.centerX(), boundsInScreen.centerY());
+ }
+ } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ // For a real view, ask the view to compute the click point.
+ succeeded = target.computeClickPointInScreenForAccessibility(
+ interactiveRegion, point);
+ }
+ }
+ } finally {
+ try {
+ Point result = null;
+ if (succeeded) {
+ applyAppScaleAndMagnificationSpecIfNeeded(point, spec);
+ result = point;
+ }
+ callback.setComputeClickPointInScreenActionResult(result, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
+ }
+ }
+
private View findViewByAccessibilityId(int accessibilityId) {
View root = mViewRootImpl.mView;
if (root == null) {
@@ -688,6 +776,26 @@ final class AccessibilityInteractionController {
}
}
+ private void applyAppScaleAndMagnificationSpecIfNeeded(Point point,
+ MagnificationSpec spec) {
+ final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
+ if (!shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
+ return;
+ }
+
+ if (applicationScale != 1.0f) {
+ point.x *= applicationScale;
+ point.y *= applicationScale;
+ }
+
+ if (spec != null) {
+ point.x *= spec.scale;
+ point.y *= spec.scale;
+ point.x += (int) spec.offsetX;
+ point.y += (int) spec.offsetY;
+ }
+ }
+
private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info,
MagnificationSpec spec) {
if (info == null) {
@@ -1080,11 +1188,12 @@ final class AccessibilityInteractionController {
private class PrivateHandler extends Handler {
private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 1;
- private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
- private final static int MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID = 3;
- private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 4;
+ private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID = 2;
+ private final static int MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID = 3;
+ private final static int MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT = 4;
private final static int MSG_FIND_FOCUS = 5;
private final static int MSG_FOCUS_SEARCH = 6;
+ private final static int MSG_COMPUTE_CLICK_POINT_IN_SCREEN = 7;
public PrivateHandler(Looper looper) {
super(looper);
@@ -1096,16 +1205,18 @@ final class AccessibilityInteractionController {
switch (type) {
case MSG_PERFORM_ACCESSIBILITY_ACTION:
return "MSG_PERFORM_ACCESSIBILITY_ACTION";
- case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
- return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
- case MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID:
- return "MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID";
- case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
- return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
+ case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID:
+ return "MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID";
+ case MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID:
+ return "MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID";
+ case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT:
+ return "MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT";
case MSG_FIND_FOCUS:
return "MSG_FIND_FOCUS";
case MSG_FOCUS_SEARCH:
return "MSG_FOCUS_SEARCH";
+ case MSG_COMPUTE_CLICK_POINT_IN_SCREEN:
+ return "MSG_COMPUTE_CLICK_POINT_IN_SCREEN";
default:
throw new IllegalArgumentException("Unknown message type: " + type);
}
@@ -1115,16 +1226,16 @@ final class AccessibilityInteractionController {
public void handleMessage(Message message) {
final int type = message.what;
switch (type) {
- case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
+ case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
findAccessibilityNodeInfoByAccessibilityIdUiThread(message);
} break;
case MSG_PERFORM_ACCESSIBILITY_ACTION: {
perfromAccessibilityActionUiThread(message);
} break;
- case MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID: {
+ case MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID: {
findAccessibilityNodeInfosByViewIdUiThread(message);
} break;
- case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
+ case MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_TEXT: {
findAccessibilityNodeInfosByTextUiThread(message);
} break;
case MSG_FIND_FOCUS: {
@@ -1133,6 +1244,9 @@ final class AccessibilityInteractionController {
case MSG_FOCUS_SEARCH: {
focusSearchUiThread(message);
} break;
+ case MSG_COMPUTE_CLICK_POINT_IN_SCREEN: {
+ computeClickPointInScreenUiThread(message);
+ } break;
default:
throw new IllegalArgumentException("Unknown message type: " + type);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5d6d998..6aa86c7 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -94,7 +94,8 @@ interface IWindowManager
void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
IRemoteCallback startedCallback, boolean scaleUp);
void overridePendingAppTransitionAspectScaledThumb(in Bitmap srcThumb, int startX,
- int startY, IRemoteCallback startedCallback, boolean scaleUp);
+ int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
+ boolean scaleUp);
void executeAppTransition();
void setAppStartingWindow(IBinder token, String pkg, int theme,
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 0f3f182..037ed28 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -177,6 +177,11 @@ interface IWindowSession {
void wallpaperOffsetsComplete(IBinder window);
+ /**
+ * Apply a raw offset to the wallpaper service when shown behind this window.
+ */
+ void setWallpaperDisplayOffset(IBinder windowToken, int x, int y);
+
Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, in Bundle extras, boolean sync);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 770e78c..82c5425 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -35,6 +35,8 @@ import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff;
@@ -5731,6 +5733,136 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Computes a point on which a sequence of a down/up event can be sent to
+ * trigger clicking this view. This method is for the exclusive use by the
+ * accessibility layer to determine where to send a click event in explore
+ * by touch mode.
+ *
+ * @param interactiveRegion The interactive portion of this window.
+ * @param outPoint The point to populate.
+ * @return True of such a point exists.
+ */
+ boolean computeClickPointInScreenForAccessibility(Region interactiveRegion,
+ Point outPoint) {
+ // Since the interactive portion of the view is a region but as a view
+ // may have a transformation matrix which cannot be applied to a
+ // region we compute the view bounds rectangle and all interactive
+ // predecessor's and sibling's (siblings of predecessors included)
+ // rectangles that intersect the view bounds. At the
+ // end if the view was partially covered by another interactive
+ // view we compute the view's interactive region and pick a point
+ // on its boundary path as regions do not offer APIs to get inner
+ // points. Note that the the code is optimized to fail early and
+ // avoid unnecessary allocations plus computations.
+
+ // The current approach has edge cases that may produce false
+ // positives or false negatives. For example, a portion of the
+ // view may be covered by an interactive descendant of a
+ // predecessor, which we do not compute. Also a view may be handling
+ // raw touch events instead registering click listeners, which
+ // we cannot compute. Despite these limitations this approach will
+ // work most of the time and it is a huge improvement over just
+ // blindly sending the down and up events in the center of the
+ // view.
+
+ // Cannot click on an unattached view.
+ if (mAttachInfo == null) {
+ return false;
+ }
+
+ // Attached to an invisible window means this view is not visible.
+ if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
+ return false;
+ }
+
+ RectF bounds = mAttachInfo.mTmpTransformRect;
+ bounds.set(0, 0, getWidth(), getHeight());
+ List<RectF> intersections = mAttachInfo.mTmpRectList;
+ intersections.clear();
+
+ if (mParent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) mParent;
+ if (!parentGroup.translateBoundsAndIntersectionsInWindowCoordinates(
+ this, bounds, intersections)) {
+ intersections.clear();
+ return false;
+ }
+ }
+
+ // Take into account the window location.
+ final int dx = mAttachInfo.mWindowLeft;
+ final int dy = mAttachInfo.mWindowTop;
+ bounds.offset(dx, dy);
+ offsetRects(intersections, dx, dy);
+
+ if (intersections.isEmpty() && interactiveRegion == null) {
+ outPoint.set((int) bounds.centerX(), (int) bounds.centerY());
+ } else {
+ // This view is partially covered by other views, then compute
+ // the not covered region and pick a point on its boundary.
+ Region region = new Region();
+ region.set((int) bounds.left, (int) bounds.top,
+ (int) bounds.right, (int) bounds.bottom);
+
+ final int intersectionCount = intersections.size();
+ for (int i = intersectionCount - 1; i >= 0; i--) {
+ RectF intersection = intersections.remove(i);
+ region.op((int) intersection.left, (int) intersection.top,
+ (int) intersection.right, (int) intersection.bottom,
+ Region.Op.DIFFERENCE);
+ }
+
+ // If the view is completely covered, done.
+ if (region.isEmpty()) {
+ return false;
+ }
+
+ // Take into account the interactive portion of the window
+ // as the rest is covered by other windows. If no such a region
+ // then the whole window is interactive.
+ if (interactiveRegion != null) {
+ region.op(interactiveRegion, Region.Op.INTERSECT);
+ }
+
+ // If the view is completely covered, done.
+ if (region.isEmpty()) {
+ return false;
+ }
+
+ // Try a shortcut here.
+ if (region.isRect()) {
+ Rect regionBounds = mAttachInfo.mTmpInvalRect;
+ region.getBounds(regionBounds);
+ outPoint.set(regionBounds.centerX(), regionBounds.centerY());
+ return true;
+ }
+
+ // Get the a point on the region boundary path.
+ Path path = region.getBoundaryPath();
+ PathMeasure pathMeasure = new PathMeasure(path, false);
+ final float[] coordinates = mAttachInfo.mTmpTransformLocation;
+
+ // Without loss of generality pick a point.
+ final float point = pathMeasure.getLength() * 0.01f;
+ if (!pathMeasure.getPosTan(point, coordinates, null)) {
+ return false;
+ }
+
+ outPoint.set(Math.round(coordinates[0]), Math.round(coordinates[1]));
+ }
+
+ return true;
+ }
+
+ static void offsetRects(List<RectF> rects, float offsetX, float offsetY) {
+ final int rectCount = rects.size();
+ for (int i = 0; i < rectCount; i++) {
+ RectF intersection = rects.get(i);
+ intersection.offset(offsetX, offsetY);
+ }
+ }
+
+ /**
* Returns the delegate for implementing accessibility support via
* composition. For more details see {@link AccessibilityDelegate}.
*
@@ -20154,6 +20286,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final RectF mTmpTransformRect = new RectF();
/**
+ * Temporary for use in computing hit areas with transformed views
+ */
+ final RectF mTmpTransformRect1 = new RectF();
+
+ /**
+ * Temporary list of rectanges.
+ */
+ final List<RectF> mTmpRectList = new ArrayList<>();
+
+ /**
* Temporary for use in transforming invalidation rect
*/
final Matrix mTmpMatrix = new Matrix();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c1e66de..4e1db90 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -771,6 +771,112 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
+ * Translates the given bounds and intersections from child coordinates to
+ * local coordinates. In case any interactive sibling of the calling child
+ * covers the latter, a new intersections is added to the intersection list.
+ * This method is for the exclusive use by the accessibility layer to compute
+ * a point where a sequence of down and up events would click on a view.
+ *
+ * @param child The child making the call.
+ * @param bounds The bounds to translate in child coordinates.
+ * @param intersections The intersections of interactive views covering the child.
+ * @return True if the bounds and intersections were computed, false otherwise.
+ */
+ boolean translateBoundsAndIntersectionsInWindowCoordinates(View child,
+ RectF bounds, List<RectF> intersections) {
+ // Not attached, done.
+ if (mAttachInfo == null) {
+ return false;
+ }
+
+ if (getAlpha() <= 0 || getTransitionAlpha() <= 0 ||
+ getVisibility() != VISIBLE) {
+ // Cannot click on a view with an invisible predecessor.
+ return false;
+ }
+
+ // Compensate for the child transformation.
+ if (!child.hasIdentityMatrix()) {
+ Matrix matrix = child.getMatrix();
+ matrix.mapRect(bounds);
+ final int intersectionCount = intersections.size();
+ for (int i = 0; i < intersectionCount; i++) {
+ RectF intersection = intersections.get(i);
+ matrix.mapRect(intersection);
+ }
+ }
+
+ // Translate the bounds from child to parent coordinates.
+ final int dx = child.mLeft - mScrollX;
+ final int dy = child.mTop - mScrollY;
+ bounds.offset(dx, dy);
+ offsetRects(intersections, dx, dy);
+
+ // If the bounds do not intersect our bounds, done.
+ if (!bounds.intersects(0, 0, getWidth(), getHeight())) {
+ return false;
+ }
+
+ // Check whether any clickable siblings cover the child
+ // view and if so keep track of the intersections. Also
+ // respect Z ordering when iterating over children.
+ ArrayList<View> orderedList = buildOrderedChildList();
+ final boolean useCustomOrder = orderedList == null
+ && isChildrenDrawingOrderEnabled();
+
+ final int childCount = mChildrenCount;
+ for (int i = childCount - 1; i >= 0; i--) {
+ final int childIndex = useCustomOrder
+ ? getChildDrawingOrder(childCount, i) : i;
+ final View sibling = (orderedList == null)
+ ? mChildren[childIndex] : orderedList.get(childIndex);
+
+ // We care only about siblings over the child.
+ if (sibling == child) {
+ break;
+ }
+
+ // If sibling is not interactive we do not care.
+ if (!sibling.isClickable() && !sibling.isLongClickable()) {
+ continue;
+ }
+
+ // Compute the sibling bounds in its coordinates.
+ RectF siblingBounds = mAttachInfo.mTmpTransformRect1;
+ siblingBounds.set(0, 0, sibling.getWidth(), sibling.getHeight());
+
+ // Take into account the sibling transformation matrix.
+ if (!sibling.hasIdentityMatrix()) {
+ sibling.getMatrix().mapRect(siblingBounds);
+ }
+
+ // Offset the sibling to our coordinates.
+ final int siblingDx = sibling.mLeft - mScrollX;
+ final int siblingDy = sibling.mTop - mScrollY;
+ siblingBounds.offset(siblingDx, siblingDy);
+
+ // Compute the intersection between the child and the sibling.
+ if (siblingBounds.intersect(bounds)) {
+ // If an interactive sibling completely covers the child, done.
+ if (siblingBounds.equals(bounds)) {
+ return false;
+ }
+ // Keep track of the intersection rectangle.
+ RectF intersection = new RectF(siblingBounds);
+ intersections.add(intersection);
+ }
+ }
+
+ if (mParent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) mParent;
+ return parentGroup.translateBoundsAndIntersectionsInWindowCoordinates(
+ this, bounds, intersections);
+ }
+
+ return true;
+ }
+
+ /**
* Called when a child view has changed whether or not it is tracking transient state.
*/
public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4299e2e..43ab4ef 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -121,7 +121,7 @@ public final class ViewRootImpl implements ViewParent,
private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
// property used by emulator to determine display shape
- private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
+ public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
/**
* Maximum time we allow the user to roll the trackball enough to generate
@@ -6679,12 +6679,12 @@ public final class ViewRootImpl implements ViewParent,
public void performAccessibilityAction(long accessibilityNodeId, int action,
Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
- int interogatingPid, long interrogatingTid) {
+ int interrogatingPid, long interrogatingTid) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
.performAccessibilityActionClientThread(accessibilityNodeId, action, arguments,
- interactionId, callback, flags, interogatingPid, interrogatingTid);
+ interactionId, callback, flags, interrogatingPid, interrogatingTid);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
@@ -6696,6 +6696,26 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
+ public void computeClickPointInScreen(long accessibilityNodeId, Region interactiveRegion,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+ ViewRootImpl viewRootImpl = mViewRootImpl.get();
+ if (viewRootImpl != null && viewRootImpl.mView != null) {
+ viewRootImpl.getAccessibilityInteractionController()
+ .computeClickPointInScreenClientThread(accessibilityNodeId,
+ interactiveRegion, interactionId, callback, interrogatingPid,
+ interrogatingTid, spec);
+ } else {
+ // We cannot make the call and notify the caller so it does not wait.
+ try {
+ callback.setComputeClickPointInScreenActionResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
+ }
+ }
+
+ @Override
public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
String viewId, Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 571a8f0..24c3c1a 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -378,35 +378,75 @@ public final class WindowInsets {
}
/**
- * @hide
+ * Returns the top stable inset in pixels.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @return The top stable inset
*/
public int getStableInsetTop() {
return mStableInsets.top;
}
/**
- * @hide
+ * Returns the left stable inset in pixels.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @return The left stable inset
*/
public int getStableInsetLeft() {
return mStableInsets.left;
}
/**
- * @hide
+ * Returns the right stable inset in pixels.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @return The right stable inset
*/
public int getStableInsetRight() {
return mStableInsets.right;
}
/**
- * @hide
+ * Returns the bottom stable inset in pixels.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @return The bottom stable inset
*/
public int getStableInsetBottom() {
return mStableInsets.bottom;
}
/**
- * @hide
+ * Returns true if this WindowInsets has nonzero stable insets.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @return true if any of the stable inset values are nonzero
*/
public boolean hasStableInsets() {
return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0
@@ -414,7 +454,9 @@ public final class WindowInsets {
}
/**
- * @hide
+ * Returns a copy of this WindowInsets with the stable insets fully consumed.
+ *
+ * @return A modified copy of this WindowInsets
*/
public WindowInsets consumeStableInsets() {
final WindowInsets result = new WindowInsets(this);
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index db78ec5..374f7e0 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -17,6 +17,7 @@
package android.view.accessibility;
import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.graphics.Point;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -98,6 +99,8 @@ public final class AccessibilityInteractionClient
private boolean mPerformAccessibilityActionResult;
+ private Point mComputeClickPointResult;
+
private Message mSameThreadMessage;
private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
@@ -519,6 +522,43 @@ public final class AccessibilityInteractionClient
return false;
}
+ /**
+ * Computes a point in screen coordinates where sending a down/up events would
+ * perform a click on an {@link AccessibilityNodeInfo}.
+ *
+ * @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+ * to start from the root.
+ * @return Point the click point of null if no such point.
+ */
+ public Point computeClickPointInScreen(int connectionId, int accessibilityWindowId,
+ long accessibilityNodeId) {
+ try {
+ IAccessibilityServiceConnection connection = getConnection(connectionId);
+ if (connection != null) {
+ final int interactionId = mInteractionIdCounter.getAndIncrement();
+ final boolean success = connection.computeClickPointInScreen(
+ accessibilityWindowId, accessibilityNodeId,
+ interactionId, this, Thread.currentThread().getId());
+ if (success) {
+ return getComputeClickPointInScreenResultAndClear(interactionId);
+ }
+ } else {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
+ }
+ }
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while calling remote computeClickPointInScreen", re);
+ }
+ return null;
+ }
+
public void clearCache() {
sAccessibilityCache.clear();
}
@@ -634,6 +674,34 @@ public final class AccessibilityInteractionClient
}
/**
+ * Gets the result of a request to compute a point in screen for clicking on a node.
+ *
+ * @param interactionId The interaction id to match the result with the request.
+ * @return The point or null if no such point.
+ */
+ private Point getComputeClickPointInScreenResultAndClear(int interactionId) {
+ synchronized (mInstanceLock) {
+ final boolean success = waitForResultTimedLocked(interactionId);
+ Point result = success ? mComputeClickPointResult : null;
+ clearResultLocked();
+ return result;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setComputeClickPointInScreenActionResult(Point point, int interactionId) {
+ synchronized (mInstanceLock) {
+ if (interactionId > mInteractionId) {
+ mComputeClickPointResult = point;
+ mInteractionId = interactionId;
+ }
+ mInstanceLock.notifyAll();
+ }
+ }
+
+ /**
* Clears the result state.
*/
private void clearResultLocked() {
@@ -641,6 +709,7 @@ public final class AccessibilityInteractionClient
mFindAccessibilityNodeInfoResult = null;
mFindAccessibilityNodeInfosResult = null;
mPerformAccessibilityActionResult = false;
+ mComputeClickPointResult = null;
}
/**
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index faf7789..66a3f46 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -17,6 +17,7 @@
package android.view.accessibility;
import android.graphics.Region;
+import android.graphics.Point;
import android.os.Bundle;
import android.view.MagnificationSpec;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -53,4 +54,8 @@ oneway interface IAccessibilityInteractionConnection {
void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid);
+
+ void computeClickPointInScreen(long accessibilityNodeId, in Region bounds, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+ long interrogatingTid, in MagnificationSpec spec);
}
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index c1a3ab7..f480216 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -16,6 +16,7 @@
package android.view.accessibility;
+import android.graphics.Point;
import android.view.accessibility.AccessibilityNodeInfo;
import java.util.List;
@@ -51,4 +52,12 @@ oneway interface IAccessibilityInteractionConnectionCallback {
* @param interactionId The interaction id to match the result with the request.
*/
void setPerformAccessibilityActionResult(boolean succeeded, int interactionId);
+
+ /**
+ * Sets the result of a request to compute a point for clicking in a view.
+ *
+ * @param point The point of null if no such point.
+ * @param interactionId The interaction id to match the result with the request.
+ */
+ void setComputeClickPointInScreenActionResult(in Point point, int interactionId);
}
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index fe0f5b9..600fffe 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -35,9 +35,21 @@ import java.util.Objects;
* actually inserted.</p>
*/
public final class CursorAnchorInfo implements Parcelable {
+ /**
+ * The index of the first character of the selected text (inclusive). {@code -1} when there is
+ * no text selection.
+ */
private final int mSelectionStart;
+ /**
+ * The index of the first character of the selected text (exclusive). {@code -1} when there is
+ * no text selection.
+ */
private final int mSelectionEnd;
+ /**
+ * The index of the first character of the composing text (inclusive). {@code -1} when there is
+ * no composing text.
+ */
private final int mComposingTextStart;
/**
* The text, tracked as a composing region.
@@ -82,7 +94,7 @@ public final class CursorAnchorInfo implements Parcelable {
* Java chars, in the local coordinates that will be transformed with the transformation matrix
* when rendered on the screen.
*/
- private final SparseRectFArray mCharacterRects;
+ private final SparseRectFArray mCharacterBoundsArray;
/**
* Transformation matrix that is applied to any positional information of this class to
@@ -91,18 +103,24 @@ public final class CursorAnchorInfo implements Parcelable {
private final Matrix mMatrix;
/**
- * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the
+ * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterBoundsFlags(int)}: the
* insertion marker or character bounds have at least one visible region.
*/
public static final int FLAG_HAS_VISIBLE_REGION = 0x01;
/**
- * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the
+ * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterBoundsFlags(int)}: the
* insertion marker or character bounds have at least one invisible (clipped) region.
*/
public static final int FLAG_HAS_INVISIBLE_REGION = 0x02;
/**
+ * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterBoundsFlags(int)}: the
+ * insertion marker or character bounds is placed at right-to-left (RTL) character.
+ */
+ public static final int FLAG_IS_RTL = 0x04;
+
+ /**
* @removed
*/
public static final int CHARACTER_RECT_TYPE_MASK = 0x0f;
@@ -144,7 +162,7 @@ public final class CursorAnchorInfo implements Parcelable {
mInsertionMarkerTop = source.readFloat();
mInsertionMarkerBaseline = source.readFloat();
mInsertionMarkerBottom = source.readFloat();
- mCharacterRects = source.readParcelable(SparseRectFArray.class.getClassLoader());
+ mCharacterBoundsArray = source.readParcelable(SparseRectFArray.class.getClassLoader());
mMatrix = new Matrix();
mMatrix.setValues(source.createFloatArray());
}
@@ -166,7 +184,7 @@ public final class CursorAnchorInfo implements Parcelable {
dest.writeFloat(mInsertionMarkerTop);
dest.writeFloat(mInsertionMarkerBaseline);
dest.writeFloat(mInsertionMarkerBottom);
- dest.writeParcelable(mCharacterRects, flags);
+ dest.writeParcelable(mCharacterBoundsArray, flags);
final float[] matrixArray = new float[9];
mMatrix.getValues(matrixArray);
dest.writeFloatArray(matrixArray);
@@ -174,7 +192,6 @@ public final class CursorAnchorInfo implements Parcelable {
@Override
public int hashCode(){
- // TODO: Improve the hash function.
final float floatHash = mInsertionMarkerHorizontal + mInsertionMarkerTop
+ mInsertionMarkerBaseline + mInsertionMarkerBottom;
int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
@@ -185,7 +202,7 @@ public final class CursorAnchorInfo implements Parcelable {
hash *= 31;
hash += Objects.hashCode(mComposingText);
hash *= 31;
- hash += Objects.hashCode(mCharacterRects);
+ hash += Objects.hashCode(mCharacterBoundsArray);
hash *= 31;
hash += Objects.hashCode(mMatrix);
return hash;
@@ -231,7 +248,7 @@ public final class CursorAnchorInfo implements Parcelable {
|| !areSameFloatImpl(mInsertionMarkerBottom, that.mInsertionMarkerBottom)) {
return false;
}
- if (!Objects.equals(mCharacterRects, that.mCharacterRects)) {
+ if (!Objects.equals(mCharacterBoundsArray, that.mCharacterBoundsArray)) {
return false;
}
if (!Objects.equals(mMatrix, that.mMatrix)) {
@@ -250,7 +267,7 @@ public final class CursorAnchorInfo implements Parcelable {
+ " mInsertionMarkerTop=" + mInsertionMarkerTop
+ " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
+ " mInsertionMarkerBottom=" + mInsertionMarkerBottom
- + " mCharacterRects=" + Objects.toString(mCharacterRects)
+ + " mCharacterBoundsArray=" + Objects.toString(mCharacterBoundsArray)
+ " mMatrix=" + Objects.toString(mMatrix)
+ "}";
}
@@ -259,6 +276,19 @@ public final class CursorAnchorInfo implements Parcelable {
* Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
*/
public static final class Builder {
+ private int mSelectionStart = -1;
+ private int mSelectionEnd = -1;
+ private int mComposingTextStart = -1;
+ private CharSequence mComposingText = null;
+ private float mInsertionMarkerHorizontal = Float.NaN;
+ private float mInsertionMarkerTop = Float.NaN;
+ private float mInsertionMarkerBaseline = Float.NaN;
+ private float mInsertionMarkerBottom = Float.NaN;
+ private int mInsertionMarkerFlags = 0;
+ private SparseRectFArrayBuilder mCharacterBoundsArrayBuilder = null;
+ private final Matrix mMatrix = new Matrix(Matrix.IDENTITY_MATRIX);
+ private boolean mMatrixInitialized = false;
+
/**
* Sets the text range of the selection. Calling this can be skipped if there is no
* selection.
@@ -268,8 +298,6 @@ public final class CursorAnchorInfo implements Parcelable {
mSelectionEnd = newEnd;
return this;
}
- private int mSelectionStart = -1;
- private int mSelectionEnd = -1;
/**
* Sets the text range of the composing text. Calling this can be skipped if there is
@@ -288,8 +316,6 @@ public final class CursorAnchorInfo implements Parcelable {
}
return this;
}
- private int mComposingTextStart = -1;
- private CharSequence mComposingText = null;
/**
* @removed
@@ -335,11 +361,33 @@ public final class CursorAnchorInfo implements Parcelable {
mInsertionMarkerFlags = flags;
return this;
}
- private float mInsertionMarkerHorizontal = Float.NaN;
- private float mInsertionMarkerTop = Float.NaN;
- private float mInsertionMarkerBaseline = Float.NaN;
- private float mInsertionMarkerBottom = Float.NaN;
- private int mInsertionMarkerFlags = 0;
+
+ /**
+ * Adds the bounding box of the character specified with the index.
+ *
+ * @param index index of the character in Java chars units. Must be specified in
+ * ascending order across successive calls.
+ * @param left x coordinate of the left edge of the character in local coordinates.
+ * @param top y coordinate of the top edge of the character in local coordinates.
+ * @param right x coordinate of the right edge of the character in local coordinates.
+ * @param bottom y coordinate of the bottom edge of the character in local coordinates.
+ * @param flags flags for this character bounds. See {@link #FLAG_HAS_VISIBLE_REGION},
+ * {@link #FLAG_HAS_INVISIBLE_REGION} and {@link #FLAG_IS_RTL}. These flags must be
+ * specified when necessary.
+ * @throws IllegalArgumentException If the index is a negative value, or not greater than
+ * all of the previously called indices.
+ */
+ public Builder addCharacterBounds(final int index, final float left, final float top,
+ final float right, final float bottom, final int flags) {
+ if (index < 0) {
+ throw new IllegalArgumentException("index must not be a negative integer.");
+ }
+ if (mCharacterBoundsArrayBuilder == null) {
+ mCharacterBoundsArrayBuilder = new SparseRectFArrayBuilder();
+ }
+ mCharacterBoundsArrayBuilder.append(index, left, top, right, bottom, flags);
+ return this;
+ }
/**
* Adds the bounding box of the character specified with the index.
@@ -358,21 +406,25 @@ public final class CursorAnchorInfo implements Parcelable {
* example.
* @throws IllegalArgumentException If the index is a negative value, or not greater than
* all of the previously called indices.
+ * @removed
*/
public Builder addCharacterRect(final int index, final float leadingEdgeX,
final float leadingEdgeY, final float trailingEdgeX, final float trailingEdgeY,
final int flags) {
- if (index < 0) {
- throw new IllegalArgumentException("index must not be a negative integer.");
- }
- if (mCharacterRectBuilder == null) {
- mCharacterRectBuilder = new SparseRectFArrayBuilder();
+ final int newFlags;
+ final float left;
+ final float right;
+ if (leadingEdgeX <= trailingEdgeX) {
+ newFlags = flags;
+ left = leadingEdgeX;
+ right = trailingEdgeX;
+ } else {
+ newFlags = flags | FLAG_IS_RTL;
+ left = trailingEdgeX;
+ right = leadingEdgeX;
}
- mCharacterRectBuilder.append(index, leadingEdgeX, leadingEdgeY, trailingEdgeX,
- trailingEdgeY, flags);
- return this;
+ return addCharacterBounds(index, left, leadingEdgeY, right, trailingEdgeY, newFlags);
}
- private SparseRectFArrayBuilder mCharacterRectBuilder = null;
/**
* Sets the matrix that transforms local coordinates into screen coordinates.
@@ -384,8 +436,6 @@ public final class CursorAnchorInfo implements Parcelable {
mMatrixInitialized = true;
return this;
}
- private final Matrix mMatrix = new Matrix(Matrix.IDENTITY_MATRIX);
- private boolean mMatrixInitialized = false;
/**
* @return {@link CursorAnchorInfo} using parameters in this {@link Builder}.
@@ -394,13 +444,15 @@ public final class CursorAnchorInfo implements Parcelable {
*/
public CursorAnchorInfo build() {
if (!mMatrixInitialized) {
- // Coordinate transformation matrix is mandatory when positional parameters are
- // specified.
- if ((mCharacterRectBuilder != null && !mCharacterRectBuilder.isEmpty()) ||
- !Float.isNaN(mInsertionMarkerHorizontal) ||
- !Float.isNaN(mInsertionMarkerTop) ||
- !Float.isNaN(mInsertionMarkerBaseline) ||
- !Float.isNaN(mInsertionMarkerBottom)) {
+ // Coordinate transformation matrix is mandatory when at least one positional
+ // parameter is specified.
+ final boolean hasCharacterBounds = (mCharacterBoundsArrayBuilder != null
+ && !mCharacterBoundsArrayBuilder.isEmpty());
+ if (hasCharacterBounds
+ || !Float.isNaN(mInsertionMarkerHorizontal)
+ || !Float.isNaN(mInsertionMarkerTop)
+ || !Float.isNaN(mInsertionMarkerBaseline)
+ || !Float.isNaN(mInsertionMarkerBottom)) {
throw new IllegalArgumentException("Coordinate transformation matrix is " +
"required when positional parameters are specified.");
}
@@ -424,8 +476,8 @@ public final class CursorAnchorInfo implements Parcelable {
mInsertionMarkerBottom = Float.NaN;
mMatrix.set(Matrix.IDENTITY_MATRIX);
mMatrixInitialized = false;
- if (mCharacterRectBuilder != null) {
- mCharacterRectBuilder.reset();
+ if (mCharacterBoundsArrayBuilder != null) {
+ mCharacterBoundsArrayBuilder.reset();
}
}
}
@@ -440,8 +492,8 @@ public final class CursorAnchorInfo implements Parcelable {
mInsertionMarkerTop = builder.mInsertionMarkerTop;
mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
- mCharacterRects = builder.mCharacterRectBuilder != null ?
- builder.mCharacterRectBuilder.build() : null;
+ mCharacterBoundsArray = builder.mCharacterBoundsArrayBuilder != null ?
+ builder.mCharacterBoundsArrayBuilder.build() : null;
mMatrix = new Matrix(builder.mMatrix);
}
@@ -539,6 +591,19 @@ public final class CursorAnchorInfo implements Parcelable {
/**
* Returns a new instance of {@link RectF} that indicates the location of the character
* specified with the index.
+ * @param index index of the character in a Java chars.
+ * @return the character bounds in local coordinates as a new instance of {@link RectF}.
+ */
+ public RectF getCharacterBounds(final int index) {
+ if (mCharacterBoundsArray == null) {
+ return null;
+ }
+ return mCharacterBoundsArray.get(index);
+ }
+
+ /**
+ * Returns a new instance of {@link RectF} that indicates the location of the character
+ * specified with the index.
* <p>
* Note that coordinates are not necessarily contiguous or even monotonous, especially when
* RTL text and LTR text are mixed.
@@ -549,28 +614,32 @@ public final class CursorAnchorInfo implements Parcelable {
* the location. Note that the {@code left} field can be greater than the {@code right} field
* if the character is in RTL text. Returns {@code null} if no location information is
* available.
+ * @removed
*/
- // TODO: Prepare a document about the expected behavior for surrogate pairs, combining
- // characters, and non-graphical chars.
public RectF getCharacterRect(final int index) {
- if (mCharacterRects == null) {
- return null;
+ return getCharacterBounds(index);
+ }
+
+ /**
+ * Returns the flags associated with the character bounds specified with the index.
+ * @param index index of the character in a Java chars.
+ * @return {@code 0} if no flag is specified.
+ */
+ public int getCharacterBoundsFlags(final int index) {
+ if (mCharacterBoundsArray == null) {
+ return 0;
}
- return mCharacterRects.get(index);
+ return mCharacterBoundsArray.getFlags(index, 0);
}
/**
* Returns the flags associated with the character rect specified with the index.
* @param index index of the character in a Java chars.
* @return {@code 0} if no flag is specified.
+ * @removed
*/
- // TODO: Prepare a document about the expected behavior for surrogate pairs, combining
- // characters, and non-graphical chars.
public int getCharacterRectFlags(final int index) {
- if (mCharacterRects == null) {
- return 0;
- }
- return mCharacterRects.getFlags(index, 0);
+ return getCharacterBoundsFlags(index);
}
/**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index eef8554..94d52d5 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3325,8 +3325,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
if (dispatchNestedPreScroll(0, -rawDeltaY, mScrollConsumed, mScrollOffset)) {
rawDeltaY += mScrollConsumed[1];
- scrollOffsetCorrection -= mScrollOffset[1];
- scrollConsumedCorrection -= mScrollConsumed[1];
+ scrollOffsetCorrection = -mScrollOffset[1];
+ scrollConsumedCorrection = mScrollConsumed[1];
if (vtev != null) {
vtev.offsetLocation(0, mScrollOffset[1]);
}
@@ -3437,7 +3437,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
}
- mMotionY = y + scrollOffsetCorrection;
+ mMotionY = y + lastYCorrection + scrollOffsetCorrection;
}
mLastY = y + lastYCorrection + scrollOffsetCorrection;
}
@@ -3505,10 +3505,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mMotionCorrection = 0;
View motionView = getChildAt(motionPosition - mFirstPosition);
mMotionViewOriginalTop = motionView != null ? motionView.getTop() : 0;
- mMotionY = y;
+ mMotionY = y + scrollOffsetCorrection;
mMotionPosition = motionPosition;
}
- mLastY = y;
+ mLastY = y + lastYCorrection + scrollOffsetCorrection;
mDirection = newDirection;
}
}
@@ -3876,7 +3876,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mPositionScroller != null) {
mPositionScroller.stop();
}
- if (flingVelocity) {
+ if (flingVelocity && !dispatchNestedPreFling(0, -initialVelocity)) {
dispatchNestedFling(0, -initialVelocity, false);
}
}
@@ -4001,14 +4001,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* <p>Applications can use this method to manually initiate a fling as if the user
* initiated it via touch interaction.</p>
*
- * @param velocityY Vertical velocity in pixels per second
+ * @param velocityY Vertical velocity in pixels per second. Note that this is velocity of
+ * content, not velocity of a touch that initiated the fling.
*/
public void fling(int velocityY) {
if (mFlingRunnable == null) {
mFlingRunnable = new FlingRunnable();
}
reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
- mFlingRunnable.start(-velocityY);
+ mFlingRunnable.start(velocityY);
}
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 2729bd0..d77f0b2 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -125,6 +125,7 @@ public class DatePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyleAttr, defStyleRes);
final int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
+ final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
a.recycle();
switch (mode) {
@@ -136,6 +137,10 @@ public class DatePicker extends FrameLayout {
mDelegate = createSpinnerUIDelegate(context, attrs, defStyleAttr, defStyleRes);
break;
}
+
+ if (firstDayOfWeek != 0) {
+ setFirstDayOfWeek(firstDayOfWeek);
+ }
}
private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
@@ -300,6 +305,47 @@ public class DatePicker extends FrameLayout {
}
/**
+ * Sets the first day of week.
+ *
+ * @param firstDayOfWeek The first day of the week conforming to the
+ * {@link CalendarView} APIs.
+ * @see Calendar#SUNDAY
+ * @see Calendar#MONDAY
+ * @see Calendar#TUESDAY
+ * @see Calendar#WEDNESDAY
+ * @see Calendar#THURSDAY
+ * @see Calendar#FRIDAY
+ * @see Calendar#SATURDAY
+ *
+ * @attr ref android.R.styleable#DatePicker_firstDayOfWeek
+ */
+ public void setFirstDayOfWeek(int firstDayOfWeek) {
+ if (firstDayOfWeek < Calendar.SUNDAY || firstDayOfWeek > Calendar.SATURDAY) {
+ throw new IllegalArgumentException("firstDayOfWeek must be between 1 and 7");
+ }
+ mDelegate.setFirstDayOfWeek(firstDayOfWeek);
+ }
+
+ /**
+ * Gets the first day of week.
+ *
+ * @return The first day of the week conforming to the {@link CalendarView}
+ * APIs.
+ * @see Calendar#SUNDAY
+ * @see Calendar#MONDAY
+ * @see Calendar#TUESDAY
+ * @see Calendar#WEDNESDAY
+ * @see Calendar#THURSDAY
+ * @see Calendar#FRIDAY
+ * @see Calendar#SATURDAY
+ *
+ * @attr ref android.R.styleable#DatePicker_firstDayOfWeek
+ */
+ public int getFirstDayOfWeek() {
+ return mDelegate.getFirstDayOfWeek();
+ }
+
+ /**
* Gets whether the {@link CalendarView} is shown.
*
* @return True if the calendar view is shown.
@@ -315,7 +361,7 @@ public class DatePicker extends FrameLayout {
* @return The calendar view.
* @see #getCalendarViewShown()
*/
- public CalendarView getCalendarView () {
+ public CalendarView getCalendarView() {
return mDelegate.getCalendarView();
}
@@ -382,6 +428,9 @@ public class DatePicker extends FrameLayout {
int getMonth();
int getDayOfMonth();
+ void setFirstDayOfWeek(int firstDayOfWeek);
+ int getFirstDayOfWeek();
+
void setMinDate(long minDate);
Calendar getMinDate();
@@ -699,6 +748,16 @@ public class DatePicker extends FrameLayout {
}
@Override
+ public void setFirstDayOfWeek(int firstDayOfWeek) {
+ mCalendarView.setFirstDayOfWeek(firstDayOfWeek);
+ }
+
+ @Override
+ public int getFirstDayOfWeek() {
+ return mCalendarView.getFirstDayOfWeek();
+ }
+
+ @Override
public void setMinDate(long minDate) {
mTempDate.setTimeInMillis(minDate);
if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index eed49bf..b962962 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -49,6 +49,7 @@ import java.util.Locale;
*/
class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate implements
View.OnClickListener, DatePickerController {
+ private static final int USE_LOCALE = 0;
private static final int UNINITIALIZED = -1;
private static final int MONTH_AND_DAY_VIEW = 0;
@@ -99,6 +100,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
private Calendar mMinDate;
private Calendar mMaxDate;
+ private int mFirstDayOfWeek = USE_LOCALE;
+
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
@@ -438,7 +441,15 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
@Override
+ public void setFirstDayOfWeek(int firstDayOfWeek) {
+ mFirstDayOfWeek = firstDayOfWeek;
+ }
+
+ @Override
public int getFirstDayOfWeek() {
+ if (mFirstDayOfWeek != USE_LOCALE) {
+ return mFirstDayOfWeek;
+ }
return mCurrentDate.getFirstDayOfWeek();
}
diff --git a/core/java/android/widget/DatePickerController.java b/core/java/android/widget/DatePickerController.java
index 6a074da..059709d 100644
--- a/core/java/android/widget/DatePickerController.java
+++ b/core/java/android/widget/DatePickerController.java
@@ -35,6 +35,7 @@ interface DatePickerController {
Calendar getSelectedDay();
+ void setFirstDayOfWeek(int firstDayOfWeek);
int getFirstDayOfWeek();
int getMinYear();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 22138d0..3f168e8 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3060,47 +3060,69 @@ public class Editor {
final CharSequence composingText = text.subSequence(composingTextStart,
composingTextEnd);
builder.setComposingText(composingTextStart, composingText);
- }
- // TODO: Optimize this loop by caching the result.
- for (int offset = composingTextStart; offset < composingTextEnd; offset++) {
- if (offset < 0) {
- continue;
- }
- final boolean isRtl = layout.isRtlCharAt(offset);
- final int line = layout.getLineForOffset(offset);
- final int nextCharIndex = offset + 1;
- final float localLeadingEdgeX = layout.getPrimaryHorizontal(offset);
- final float localTrailingEdgeX;
- if (nextCharIndex != layout.getLineEnd(line)) {
- localTrailingEdgeX = layout.getPrimaryHorizontal(nextCharIndex);
- } else if (isRtl) {
- localTrailingEdgeX = layout.getLineLeft(line);
- } else {
- localTrailingEdgeX = layout.getLineRight(line);
- }
- final float leadingEdgeX = localLeadingEdgeX
- + viewportToContentHorizontalOffset;
- final float trailingEdgeX = localTrailingEdgeX
- + viewportToContentHorizontalOffset;
- final float top = layout.getLineTop(line) + viewportToContentVerticalOffset;
- final float bottom = layout.getLineBottom(line)
- + viewportToContentVerticalOffset;
- // TODO: Check right-top and left-bottom as well.
- final boolean isLeadingEdgeTopVisible = isPositionVisible(leadingEdgeX, top);
- final boolean isTrailingEdgeBottomVisible =
- isPositionVisible(trailingEdgeX, bottom);
- int characterRectFlags = 0;
- if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) {
- characterRectFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
- }
- if (!isLeadingEdgeTopVisible || !isTrailingEdgeBottomVisible) {
- characterRectFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+
+ final int minLine = layout.getLineForOffset(composingTextStart);
+ final int maxLine = layout.getLineForOffset(composingTextEnd - 1);
+ for (int line = minLine; line <= maxLine; ++line) {
+ final int lineStart = layout.getLineStart(line);
+ final int lineEnd = layout.getLineEnd(line);
+ final int offsetStart = Math.max(lineStart, composingTextStart);
+ final int offsetEnd = Math.min(lineEnd, composingTextEnd);
+ final boolean ltrLine =
+ layout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
+ final float[] widths = new float[offsetEnd - offsetStart];
+ layout.getPaint().getTextWidths(text, offsetStart, offsetEnd, widths);
+ final float top = layout.getLineTop(line);
+ final float bottom = layout.getLineBottom(line);
+ for (int offset = offsetStart; offset < offsetEnd; ++offset) {
+ final float charWidth = widths[offset - offsetStart];
+ final boolean isRtl = layout.isRtlCharAt(offset);
+ final float primary = layout.getPrimaryHorizontal(offset);
+ final float secondary = layout.getSecondaryHorizontal(offset);
+ // TODO: This doesn't work perfectly for text with custom styles and
+ // TAB chars.
+ final float left;
+ final float right;
+ if (ltrLine) {
+ if (isRtl) {
+ left = secondary - charWidth;
+ right = secondary;
+ } else {
+ left = primary;
+ right = primary + charWidth;
+ }
+ } else {
+ if (!isRtl) {
+ left = secondary;
+ right = secondary + charWidth;
+ } else {
+ left = primary - charWidth;
+ right = primary;
+ }
+ }
+ // TODO: Check top-right and bottom-left as well.
+ final float localLeft = left + viewportToContentHorizontalOffset;
+ final float localRight = right + viewportToContentHorizontalOffset;
+ final float localTop = top + viewportToContentVerticalOffset;
+ final float localBottom = bottom + viewportToContentVerticalOffset;
+ final boolean isTopLeftVisible = isPositionVisible(localLeft, localTop);
+ final boolean isBottomRightVisible =
+ isPositionVisible(localRight, localBottom);
+ int characterBoundsFlags = 0;
+ if (isTopLeftVisible || isBottomRightVisible) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isTopLeftVisible || !isTopLeftVisible) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+ }
+ if (isRtl) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+ }
+ // Here offset is the index in Java chars.
+ builder.addCharacterBounds(offset, localLeft, localTop, localRight,
+ localBottom, characterBoundsFlags);
+ }
}
- // Here offset is the index in Java chars.
- // TODO: We must have a well-defined specification. For example, how
- // surrogate pairs and composition letters are handled must be documented.
- builder.addCharacterRect(offset, leadingEdgeX, top, trailingEdgeX, bottom,
- characterRectFlags);
}
}
@@ -3127,6 +3149,9 @@ public class Editor {
if (!isTopVisible || !isBottomVisible) {
insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
}
+ if (layout.isRtlCharAt(offset)) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+ }
builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags);
}