summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/animation/ObjectAnimator.java3
-rw-r--r--core/java/android/animation/ValueAnimator.java3
-rw-r--r--core/java/android/annotation/CallSuper.java38
-rw-r--r--core/java/android/annotation/CheckResult.java58
-rw-r--r--core/java/android/annotation/ColorInt.java40
-rw-r--r--core/java/android/annotation/FloatRange.java55
-rw-r--r--core/java/android/annotation/IntRange.java47
-rw-r--r--core/java/android/annotation/Size.java52
-rw-r--r--core/java/android/app/Activity.java13
-rw-r--r--core/java/android/app/ActivityManager.java32
-rw-r--r--core/java/android/app/ActivityManagerNative.java63
-rw-r--r--core/java/android/app/ActivityThread.java8
-rw-r--r--core/java/android/app/AppOpsManager.java12
-rw-r--r--core/java/android/app/Dialog.java3
-rw-r--r--core/java/android/app/IActivityManager.java12
-rw-r--r--core/java/android/app/IWallpaperManager.aidl20
-rw-r--r--core/java/android/app/Instrumentation.java6
-rw-r--r--core/java/android/app/Notification.java12
-rw-r--r--core/java/android/app/WallpaperManager.java54
-rw-r--r--core/java/android/app/admin/DeviceAdminReceiver.java74
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java223
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl9
-rw-r--r--core/java/android/app/backup/BackupAgent.java11
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/UriMatcher.java5
-rw-r--r--core/java/android/content/pm/PackageManager.java4
-rw-r--r--core/java/android/content/res/ColorStateList.java6
-rw-r--r--core/java/android/content/res/Resources.java3
-rw-r--r--core/java/android/content/res/TypedArray.java4
-rw-r--r--core/java/android/gesture/GestureOverlayView.java7
-rw-r--r--core/java/android/os/BatteryStats.java33
-rw-r--r--core/java/android/os/Debug.java68
-rw-r--r--core/java/android/os/UserManager.java9
-rw-r--r--core/java/android/preference/DialogPreference.java2
-rw-r--r--core/java/android/preference/Preference.java4
-rw-r--r--core/java/android/provider/ContactsContract.java5
-rw-r--r--core/java/android/provider/DocumentsProvider.java3
-rw-r--r--core/java/android/service/chooser/ChooserTarget.aidl19
-rw-r--r--core/java/android/service/chooser/ChooserTarget.java248
-rw-r--r--core/java/android/service/chooser/ChooserTargetService.java130
-rw-r--r--core/java/android/service/chooser/IChooserTargetResult.aidl27
-rw-r--r--core/java/android/service/chooser/IChooserTargetService.aidl30
-rw-r--r--core/java/android/text/DynamicLayout.java30
-rw-r--r--core/java/android/text/MeasuredText.java25
-rw-r--r--core/java/android/text/StaticLayout.java248
-rw-r--r--core/java/android/text/TextPaint.java4
-rw-r--r--core/java/android/text/style/ForegroundColorSpan.java4
-rw-r--r--core/java/android/text/style/QuoteSpan.java4
-rw-r--r--core/java/android/util/ArraySet.java20
-rw-r--r--core/java/android/util/DebugUtils.java80
-rw-r--r--core/java/android/view/GLES20Canvas.java4
-rw-r--r--core/java/android/view/ThreadedRenderer.java4
-rw-r--r--core/java/android/view/View.java37
-rw-r--r--core/java/android/view/Window.java9
-rw-r--r--core/java/android/view/animation/Animation.java4
-rw-r--r--core/java/android/view/animation/Transformation.java3
-rw-r--r--core/java/android/webkit/WebResourceError.java39
-rw-r--r--core/java/android/webkit/WebResourceResponse.java43
-rw-r--r--core/java/android/webkit/WebResourceResponseBase.java68
-rw-r--r--core/java/android/webkit/WebSettings.java4
-rw-r--r--core/java/android/webkit/WebViewClient.java35
-rw-r--r--core/java/android/widget/AbsListView.java4
-rw-r--r--core/java/android/widget/AdapterView.java7
-rw-r--r--core/java/android/widget/CalendarView.java16
-rw-r--r--core/java/android/widget/EdgeEffect.java4
-rw-r--r--core/java/android/widget/Editor.java598
-rw-r--r--core/java/android/widget/FrameLayout.java7
-rw-r--r--core/java/android/widget/GridLayout.java66
-rw-r--r--core/java/android/widget/LinearLayout.java5
-rw-r--r--core/java/android/widget/RemoteViews.java3
-rw-r--r--core/java/android/widget/TextView.java34
-rw-r--r--core/java/android/widget/Toolbar.java5
72 files changed, 2561 insertions, 316 deletions
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 87ad49b..3f71d51 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -16,6 +16,7 @@
package android.animation;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Path;
@@ -861,6 +862,7 @@ public final class ObjectAnimator extends ValueAnimator {
* <p>Overriders of this method should call the superclass method to cause
* internal mechanisms to be set up correctly.</p>
*/
+ @CallSuper
@Override
void initAnimation() {
if (!mInitialized) {
@@ -961,6 +963,7 @@ public final class ObjectAnimator extends ValueAnimator {
*
* @param fraction The elapsed fraction of the animation.
*/
+ @CallSuper
@Override
void animateValue(float fraction) {
final Object target = getTarget();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 118af64..85dc832 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -16,6 +16,7 @@
package android.animation;
+import android.annotation.CallSuper;
import android.os.Looper;
import android.os.Trace;
import android.util.AndroidRuntimeException;
@@ -506,6 +507,7 @@ public class ValueAnimator extends Animator {
* <p>Overrides of this method should call the superclass method to ensure
* that internal mechanisms for the animation are set up correctly.</p>
*/
+ @CallSuper
void initAnimation() {
if (!mInitialized) {
int numValues = mValues.length;
@@ -1375,6 +1377,7 @@ public class ValueAnimator extends Animator {
*
* @param fraction The elapsed fraction of the animation.
*/
+ @CallSuper
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java
new file mode 100644
index 0000000..82e2723
--- /dev/null
+++ b/core/java/android/annotation/CallSuper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that any overriding methods should invoke this method as well.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * &#64;CallSuper
+ * public abstract void onFocusLost();
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CallSuper {
+} \ No newline at end of file
diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java
new file mode 100644
index 0000000..787514e
--- /dev/null
+++ b/core/java/android/annotation/CheckResult.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated method returns a result that it typically is
+ * an error to ignore. This is usually used for methods that have no side effect,
+ * so calling it without actually looking at the result usually means the developer
+ * has misunderstood what the method does.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * public &#64;CheckResult String trim(String s) { return s.trim(); }
+ * ...
+ * s.trim(); // this is probably an error
+ * s = s.trim(); // ok
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CheckResult {
+ /** Defines the name of the suggested method to use instead, if applicable (using
+ * the same signature format as javadoc.) If there is more than one possibility,
+ * list them all separated by commas.
+ * <p>
+ * For example, ProcessBuilder has a method named {@code redirectErrorStream()}
+ * which sounds like it might redirect the error stream. It does not. It's just
+ * a getter which returns whether the process builder will redirect the error stream,
+ * and to actually set it, you must call {@code redirectErrorStream(boolean)}.
+ * In that case, the method should be defined like this:
+ * <pre>
+ * &#64;CheckResult(suggest="#redirectErrorStream(boolean)")
+ * public boolean redirectErrorStream() { ... }
+ * </pre>
+ */
+ String suggest() default "";
+} \ No newline at end of file
diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java
new file mode 100644
index 0000000..c4c93ee
--- /dev/null
+++ b/core/java/android/annotation/ColorInt.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element represents a packed color
+ * int, {@code AARRGGBB}. If applied to an int array, every element
+ * in the array represents a color integer.
+ * <p>
+ * public abstract void setTextColor(&#64;ColorInt int color);
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD})
+public @interface ColorInt {
+} \ No newline at end of file
diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java
new file mode 100644
index 0000000..3a7c150
--- /dev/null
+++ b/core/java/android/annotation/FloatRange.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be a float or double in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ * &#64;FloatRange(from=0.0,to=1.0)
+ * public float getAlpha() {
+ * ...
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface FloatRange {
+ /** Smallest value. Whether it is inclusive or not is determined
+ * by {@link #fromInclusive} */
+ double from() default Double.NEGATIVE_INFINITY;
+ /** Largest value. Whether it is inclusive or not is determined
+ * by {@link #toInclusive} */
+ double to() default Double.POSITIVE_INFINITY;
+
+ /** Whether the from value is included in the range */
+ boolean fromInclusive() default true;
+
+ /** Whether the to value is included in the range */
+ boolean toInclusive() default true;
+} \ No newline at end of file
diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java
new file mode 100644
index 0000000..1e3c072
--- /dev/null
+++ b/core/java/android/annotation/IntRange.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be an int or long in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ * &#64;IntRange(from=0,to=255)
+ * public int getAlpha() {
+ * ...
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface IntRange {
+ /** Smallest value, inclusive */
+ long from() default Long.MIN_VALUE;
+ /** Largest value, inclusive */
+ long to() default Long.MAX_VALUE;
+} \ No newline at end of file
diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java
new file mode 100644
index 0000000..389b819
--- /dev/null
+++ b/core/java/android/annotation/Size.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should have a given size or length.
+ * Note that "-1" means "unset". Typically used with a parameter or
+ * return value of type array or collection.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * public void getLocationInWindow(&#64;Size(2) int[] location) {
+ * ...
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD})
+public @interface Size {
+ /** An exact size (or -1 if not specified) */
+ long value() default -1;
+ /** A minimum size, inclusive */
+ long min() default Long.MIN_VALUE;
+ /** A maximum size, inclusive */
+ long max() default Long.MAX_VALUE;
+ /** The size must be a multiple of this factor */
+ long multiple() default 1;
+} \ No newline at end of file
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a36d34a..9f8befe 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
@@ -921,6 +922,7 @@ public class Activity extends ContextThemeWrapper
* @see #onRestoreInstanceState
* @see #onPostCreate
*/
+ @CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
@@ -1122,6 +1124,7 @@ public class Activity extends ContextThemeWrapper
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
* @see #onCreate
*/
+ @CallSuper
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
if (!isChild()) {
mTitleReady = true;
@@ -1159,6 +1162,7 @@ public class Activity extends ContextThemeWrapper
* @see #onStop
* @see #onResume
*/
+ @CallSuper
protected void onStart() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
mCalled = true;
@@ -1196,6 +1200,7 @@ public class Activity extends ContextThemeWrapper
* @see #onStart
* @see #onResume
*/
+ @CallSuper
protected void onRestart() {
mCalled = true;
}
@@ -1220,6 +1225,7 @@ public class Activity extends ContextThemeWrapper
* @see #onPostResume
* @see #onPause
*/
+ @CallSuper
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
@@ -1239,6 +1245,7 @@ public class Activity extends ContextThemeWrapper
*
* @see #onResume
*/
+ @CallSuper
protected void onPostResume() {
final Window win = getWindow();
if (win != null) win.makeActive();
@@ -1464,6 +1471,7 @@ public class Activity extends ContextThemeWrapper
* @see #onSaveInstanceState
* @see #onStop
*/
+ @CallSuper
protected void onPause() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
getApplication().dispatchActivityPaused(this);
@@ -1570,6 +1578,7 @@ public class Activity extends ContextThemeWrapper
* @see #onSaveInstanceState
* @see #onDestroy
*/
+ @CallSuper
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
@@ -1607,6 +1616,7 @@ public class Activity extends ContextThemeWrapper
* @see #finish
* @see #isFinishing
*/
+ @CallSuper
protected void onDestroy() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
mCalled = true;
@@ -5587,6 +5597,7 @@ public class Activity extends ContextThemeWrapper
* @see #requestVisibleBehind(boolean)
* @see #onBackgroundVisibleBehindChanged(boolean)
*/
+ @CallSuper
public void onVisibleBehindCanceled() {
mCalled = true;
}
@@ -5709,6 +5720,7 @@ public class Activity extends ContextThemeWrapper
*
* @param mode The new action mode.
*/
+ @CallSuper
@Override
public void onActionModeStarted(ActionMode mode) {
}
@@ -5719,6 +5731,7 @@ public class Activity extends ContextThemeWrapper
*
* @param mode The action mode that just finished.
*/
+ @CallSuper
@Override
public void onActionModeFinished(ActionMode mode) {
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c6ffef6..c525ef2 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -309,6 +309,21 @@ public class ActivityManager {
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 13;
+ /**
+ * Lock task mode is not active.
+ */
+ public static final int LOCK_TASK_MODE_NONE = 0;
+
+ /**
+ * Full lock task mode is active.
+ */
+ public static final int LOCK_TASK_MODE_LOCKED = 1;
+
+ /**
+ * App pinning mode is active.
+ */
+ public static final int LOCK_TASK_MODE_PINNED = 2;
+
Point mAppTaskThumbnailSize;
/*package*/ ActivityManager(Context context, Handler handler) {
@@ -2684,12 +2699,25 @@ public class ActivityManager {
* no new tasks can be created or switched to.
*
* @see Activity#startLockTask()
+ *
+ * @deprecated Use {@link #getLockTaskModeState} instead.
*/
public boolean isInLockTaskMode() {
+ return getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+ }
+
+ /**
+ * Return the current state of task locking. The three possible outcomes
+ * are {@link #LOCK_TASK_MODE_NONE}, {@link #LOCK_TASK_MODE_LOCKED}
+ * and {@link #LOCK_TASK_MODE_PINNED}.
+ *
+ * @see Activity#startLockTask()
+ */
+ public int getLockTaskModeState() {
try {
- return ActivityManagerNative.getDefault().isInLockTaskMode();
+ return ActivityManagerNative.getDefault().getLockTaskModeState();
} catch (RemoteException e) {
- return false;
+ return ActivityManager.LOCK_TASK_MODE_NONE;
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index bb307bb..997f69d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2294,6 +2294,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_LOCK_TASK_MODE_STATE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int lockTaskModeState = getLockTaskModeState();
+ reply.writeNoException();
+ reply.writeInt(lockTaskModeState);
+ return true;
+ }
+
case SET_TASK_DESCRIPTION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -2415,6 +2423,23 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
+
+ case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String procName = data.readString();
+ long maxMemSize = data.readLong();
+ setDumpHeapDebugLimit(procName, maxMemSize);
+ reply.writeNoException();
+ return true;
+ }
+
+ case DUMP_HEAP_FINISHED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String path = data.readString();
+ dumpHeapFinished(path);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5420,6 +5445,19 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
+ public int getLockTaskModeState() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_LOCK_TASK_MODE_STATE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int lockTaskModeState = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return lockTaskModeState;
+ }
+
+ @Override
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -5595,5 +5633,30 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ @Override
+ public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(processName);
+ data.writeLong(maxMemSize);
+ mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
+ public void dumpHeapFinished(String path) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(path);
+ mRemote.transact(DUMP_HEAP_FINISHED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 653b951..97793c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -121,7 +121,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;
-import java.util.regex.Pattern;
import libcore.io.DropBox;
import libcore.io.EventLogger;
@@ -160,7 +159,6 @@ public final class ActivityThread {
private static final boolean DEBUG_MEMORY_TRIM = false;
private static final boolean DEBUG_PROVIDER = false;
private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
- private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
private static final int LOG_AM_ON_RESUME_CALLED = 30022;
@@ -4247,6 +4245,10 @@ public final class ActivityThread {
} else {
Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
}
+ try {
+ ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
+ } catch (RemoteException e) {
+ }
}
final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
@@ -4986,7 +4988,7 @@ public final class ActivityThread {
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
- final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
+ final String auths[] = holder.info.authority.split(";");
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
final ProviderClientRecord pcr = new ProviderClientRecord(
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 95870cf..4bd2332 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -206,8 +206,10 @@ public class AppOpsManager {
public static final int OP_PROJECT_MEDIA = 46;
/** @hide Activate a VPN connection without user intervention. */
public static final int OP_ACTIVATE_VPN = 47;
+ /** @hide Access the WallpaperManagerAPI to write wallpapers. */
+ public static final int OP_WRITE_WALLPAPER = 48;
/** @hide */
- public static final int _NUM_OP = 48;
+ public static final int _NUM_OP = 49;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -285,6 +287,7 @@ public class AppOpsManager {
OP_TOAST_WINDOW,
OP_PROJECT_MEDIA,
OP_ACTIVATE_VPN,
+ OP_WRITE_WALLPAPER,
};
/**
@@ -340,6 +343,7 @@ public class AppOpsManager {
null,
null,
OPSTR_ACTIVATE_VPN,
+ null,
};
/**
@@ -395,6 +399,7 @@ public class AppOpsManager {
"TOAST_WINDOW",
"PROJECT_MEDIA",
"ACTIVATE_VPN",
+ "WRITE_WALLPAPER",
};
/**
@@ -450,6 +455,7 @@ public class AppOpsManager {
null, // no permission for displaying toasts
null, // no permission for projecting media
null, // no permission for activating vpn
+ null, // no permission for supporting wallpaper
};
/**
@@ -506,6 +512,7 @@ public class AppOpsManager {
UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW
null, //PROJECT_MEDIA
UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN
+ UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
};
/**
@@ -561,6 +568,7 @@ public class AppOpsManager {
true, //TOAST_WINDOW
false, //PROJECT_MEDIA
false, //ACTIVATE_VPN
+ false, //WALLPAPER
};
/**
@@ -615,6 +623,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
+ AppOpsManager.MODE_ALLOWED,
};
/**
@@ -673,6 +682,7 @@ public class AppOpsManager {
false,
false,
false,
+ false,
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index e465d57..8e64b34 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -1010,6 +1011,7 @@ public class Dialog implements DialogInterface, Window.Callback,
* Note that if you override this method you should always call through
* to the superclass implementation by calling super.onActionModeStarted(mode).
*/
+ @CallSuper
public void onActionModeStarted(ActionMode mode) {
mActionMode = mode;
}
@@ -1020,6 +1022,7 @@ public class Dialog implements DialogInterface, Window.Callback,
* Note that if you override this method you should always call through
* to the superclass implementation by calling super.onActionModeFinished(mode).
*/
+ @CallSuper
public void onActionModeFinished(ActionMode mode) {
if (mode == mActionMode) {
mActionMode = null;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a7e9413..3dcbdd2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -461,6 +461,8 @@ public interface IActivityManager extends IInterface {
public boolean isInLockTaskMode() throws RemoteException;
+ public int getLockTaskModeState() throws RemoteException;
+
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
@@ -480,6 +482,9 @@ public interface IActivityManager extends IInterface {
public void systemBackupRestored() throws RemoteException;
public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
+ public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
+ public void dumpHeapFinished(String path) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -510,7 +515,7 @@ public interface IActivityManager extends IInterface {
dest.writeStrongBinder(null);
}
dest.writeStrongBinder(connection);
- dest.writeInt(noReleaseNeeded ? 1:0);
+ dest.writeInt(noReleaseNeeded ? 1 : 0);
}
public static final Parcelable.Creator<ContentProviderHolder> CREATOR
@@ -529,7 +534,7 @@ public interface IActivityManager extends IInterface {
private ContentProviderHolder(Parcel source) {
info = ProviderInfo.CREATOR.createFromParcel(source);
provider = ContentProviderNative.asInterface(
- source.readStrongBinder());
+ source.readStrongBinder());
connection = source.readStrongBinder();
noReleaseNeeded = source.readInt() != 0;
}
@@ -810,4 +815,7 @@ public interface IActivityManager extends IInterface {
int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
+ int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
+ int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
+ int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3b5900b..ccba250 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -29,13 +29,18 @@ interface IWallpaperManager {
/**
* Set the wallpaper.
*/
- ParcelFileDescriptor setWallpaper(String name);
+ ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
/**
* Set the live wallpaper.
*/
+ void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
+
+ /**
+ * Set the live wallpaper.
+ */
void setWallpaperComponent(in ComponentName name);
-
+
/**
* Get the wallpaper.
*/
@@ -50,7 +55,7 @@ interface IWallpaperManager {
/**
* Clear the wallpaper.
*/
- void clearWallpaper();
+ void clearWallpaper(in String callingPackage);
/**
* Return whether there is a wallpaper set with the given name.
@@ -61,7 +66,7 @@ interface IWallpaperManager {
* Sets the dimension hint for the wallpaper. These hints indicate the desired
* minimum width and height for the wallpaper.
*/
- void setDimensionHints(in int width, in int height);
+ void setDimensionHints(in int width, in int height, in String callingPackage);
/**
* Returns the desired minimum width for the wallpaper.
@@ -76,7 +81,7 @@ interface IWallpaperManager {
/**
* Sets extra padding that we would like the wallpaper to have outside of the display.
*/
- void setDisplayPadding(in Rect padding);
+ void setDisplayPadding(in Rect padding, in String callingPackage);
/**
* Returns the name of the wallpaper. Private API.
@@ -87,4 +92,9 @@ interface IWallpaperManager {
* Informs the service that wallpaper settings have been restored. Private API.
*/
void settingsRestored();
+
+ /**
+ * Check whether wallpapers are supported for the calling user.
+ */
+ boolean isWallpaperSupported(in String callingPackage);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index ad2b61f..5572d30 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1322,7 +1322,10 @@ public class Instrumentation {
/*
* Starts allocation counting. This triggers a gc and resets the counts.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public void startAllocCounting() {
// Before we start trigger a GC and reset the debug counts. Run the
// finalizers and another GC before starting and stopping the alloc
@@ -1340,7 +1343,10 @@ public class Instrumentation {
/*
* Stops allocation counting.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public void stopAllocCounting() {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9c00e1c..85a6aff 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
@@ -338,6 +339,7 @@ public class Notification implements Parcelable
* @see #FLAG_SHOW_LIGHTS
* @see #flags
*/
+ @ColorInt
public int ledARGB;
/**
@@ -415,7 +417,6 @@ public class Notification implements Parcelable
* Bit to be bitwise-ored into the {@link #flags} field that should be
* set if the notification should be canceled when it is clicked by the
* user.
-
*/
public static final int FLAG_AUTO_CANCEL = 0x00000010;
@@ -520,12 +521,14 @@ public class Notification implements Parcelable
* {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
* ignored.
*/
+ @ColorInt
public int color = COLOR_DEFAULT;
/**
* Special value of {@link #color} telling the system not to decorate this notification with
* any special color but instead use default colors when presenting this notification.
*/
+ @ColorInt
public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
/**
@@ -2388,7 +2391,7 @@ public class Notification implements Parcelable
* @see Notification#ledOnMS
* @see Notification#ledOffMS
*/
- public Builder setLights(int argb, int onMs, int offMs) {
+ public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
mLedArgb = argb;
mLedOnMs = onMs;
mLedOffMs = offMs;
@@ -2712,7 +2715,7 @@ public class Notification implements Parcelable
*
* @return The same Builder.
*/
- public Builder setColor(int argb) {
+ public Builder setColor(@ColorInt int argb) {
mColor = argb;
return this;
}
@@ -5160,7 +5163,7 @@ public class Notification implements Parcelable
* automotive setting. This method can be used to override the color provided in the
* notification in such a situation.
*/
- public CarExtender setColor(int color) {
+ public CarExtender setColor(@ColorInt int color) {
mColor = color;
return this;
}
@@ -5170,6 +5173,7 @@ public class Notification implements Parcelable
*
* @see setColor
*/
+ @ColorInt
public int getColor() {
return mColor;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index badb606..22e79b6 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -64,7 +64,10 @@ import java.util.List;
* Provides access to the system wallpaper. With WallpaperManager, you can
* get the current wallpaper, get the desired dimensions for the wallpaper, set
* the wallpaper, and more. Get an instance of WallpaperManager with
- * {@link #getInstance(android.content.Context) getInstance()}.
+ * {@link #getInstance(android.content.Context) getInstance()}.
+ *
+ * <p> An app can check whether wallpapers are supported for the current user, by calling
+ * {@link #isWallpaperSupported()}.
*/
public class WallpaperManager {
private static String TAG = "WallpaperManager";
@@ -249,6 +252,15 @@ public class WallpaperManager {
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
+ if (mService != null) {
+ try {
+ if (!mService.isWallpaperSupported(context.getOpPackageName())) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
if (mWallpaper != null) {
return mWallpaper;
}
@@ -618,7 +630,9 @@ public class WallpaperManager {
* wallpaper will require reloading it again from disk.
*/
public void forgetLoadedWallpaper() {
- sGlobals.forgetLoadedWallpaper();
+ if (isWallpaperSupported()) {
+ sGlobals.forgetLoadedWallpaper();
+ }
}
/**
@@ -717,7 +731,7 @@ public class WallpaperManager {
Resources resources = mContext.getResources();
/* Set the wallpaper to the default values */
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
- "res:" + resources.getResourceName(resid));
+ "res:" + resources.getResourceName(resid), mContext.getOpPackageName());
if (fd != null) {
FileOutputStream fos = null;
try {
@@ -753,7 +767,8 @@ public class WallpaperManager {
return;
}
try {
- ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
+ ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
+ mContext.getOpPackageName());
if (fd == null) {
return;
}
@@ -792,7 +807,8 @@ public class WallpaperManager {
return;
}
try {
- ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
+ ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
+ mContext.getOpPackageName());
if (fd == null) {
return;
}
@@ -945,7 +961,8 @@ public class WallpaperManager {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
} else {
- sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+ sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight,
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
// Ignore
@@ -966,7 +983,7 @@ public class WallpaperManager {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
} else {
- sGlobals.mService.setDisplayPadding(padding);
+ sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
}
} catch (RemoteException e) {
// Ignore
@@ -1006,7 +1023,7 @@ public class WallpaperManager {
return;
}
try {
- sGlobals.mService.clearWallpaper();
+ sGlobals.mService.clearWallpaper(mContext.getOpPackageName());
} catch (RemoteException e) {
// Ignore
}
@@ -1027,7 +1044,7 @@ public class WallpaperManager {
return false;
}
try {
- sGlobals.mService.setWallpaperComponent(name);
+ sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
// Ignore
@@ -1096,7 +1113,24 @@ public class WallpaperManager {
// Ignore.
}
}
-
+
+ /**
+ * Returns whether wallpapers are supported for the calling user. If this function returns
+ * false, any attempts to changing the wallpaper will have no effect.
+ */
+ public boolean isWallpaperSupported() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ } else {
+ try {
+ return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+ return false;
+ }
+
/**
* Clear the offsets previously associated with this window through
* {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 4fc990e..fe284ce 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -168,8 +168,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
/**
* Action sent to a device administrator to notify that the device is entering
- * lock task mode from an authorized package. The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
- * will describe the authorized package using lock task mode.
+ * lock task mode. The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
+ * will describe the package using lock task mode.
*
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
@@ -182,7 +182,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
/**
* Action sent to a device administrator to notify that the device is exiting
- * lock task mode from an authorized package.
+ * lock task mode.
*
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
@@ -215,7 +215,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
* <p>A device admin application which listens to this intent can find out if the device was
* provisioned for the device owner or profile owner case by calling respectively
* {@link android.app.admin.DevicePolicyManager#isDeviceOwnerApp} and
- * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}.
+ * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}. You will generally handle
+ * this in {@link DeviceAdminReceiver#onProfileProvisioningComplete}.
*
* <p>Input: Nothing.</p>
* <p>Output: Nothing</p>
@@ -224,6 +225,23 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
"android.app.action.PROFILE_PROVISIONING_COMPLETE";
+ /**
+ * Broadcast Action: This broadcast is sent to indicate that the system is ready for the device
+ * initializer to perform user setup tasks. This is only applicable to devices managed by a
+ * device owner app.
+ *
+ * <p>The broadcast will be limited to the {@link DeviceAdminReceiver} component specified in
+ * the (@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME) field
+ * of the original intent or NFC bump that started the provisioning process. You will generally
+ * handle this in {@link DeviceAdminReceiver#onReadyForUserInitialization}.
+ *
+ * <p>Input: Nothing.</p>
+ * <p>Output: Nothing</p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_READY_FOR_USER_INITIALIZATION =
+ "android.app.action.READY_FOR_USER_INITIALIZATION";
+
/** @hide */
public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
@@ -245,7 +263,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
/** @hide */
public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE";
- /**
+ /**
* Name under which a DevicePolicy component publishes information
* about itself. This meta-data must reference an XML resource containing
* a device-admin tag.
@@ -382,20 +400,20 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
/**
* Called when provisioning of a managed profile or managed device has completed successfully.
*
- * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
+ * <p> As a prerequisite for the execution of this callback the {@link DeviceAdminReceiver} has
* to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
* Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
* of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
* managed provisioning.
*
- * <p>When provisioning is complete, the managed profile is hidden until the profile owner
- * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
- * owner will enable the profile when it has finished any additional setup such as adding an
- * account by using the {@link AccountManager} and calling apis to bring the profile into the
- * desired state.
+ * <p>When provisioning of a managed profile is complete, the managed profile is hidden until
+ * the profile owner calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}.
+ * Typically a profile owner will enable the profile when it has finished any additional setup
+ * such as adding an account by using the {@link AccountManager} and calling apis to bring the
+ * profile into the desired state.
*
* <p> Note that provisioning completes without waiting for any server interactions, so the
- * profile owner needs to wait for data to be available if required (e.g android device ids or
+ * profile owner needs to wait for data to be available if required (e.g. android device ids or
* other data that is set as a result of server interactions).
*
* @param context The running context as per {@link #onReceive}.
@@ -405,8 +423,31 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
- * Called when a device is entering lock task mode by a package authorized
- * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+ * Called during provisioning of a managed device to allow the device initializer to perform
+ * user setup steps. Only device initializers should override this method.
+ *
+ * <p> Called when the DeviceAdminReceiver receives a
+ * {@link #ACTION_READY_FOR_USER_INITIALIZATION} broadcast. As a prerequisite for the execution
+ * of this callback the {@link DeviceAdminReceiver} has
+ * to declare an intent filter for {@link #ACTION_READY_FOR_USER_INITIALIZATION}. Only the
+ * component specified in the
+ * {@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME} field of the
+ * original intent or NFC bump that started the provisioning process will receive this callback.
+ *
+ * <p>It is not assumed that the device initializer is finished when it returns from
+ * this call, as it may do additional setup asynchronously. The device initializer must call
+ * {DevicePolicyManager#setUserEnabled(ComponentName admin)} when it has finished any additional
+ * setup (such as adding an account by using the {@link AccountManager}) in order for the user
+ * to be functional.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ */
+ public void onReadyForUserInitialization(Context context, Intent intent) {
+ }
+
+ /**
+ * Called when a device is entering lock task mode.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
@@ -416,8 +457,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
/**
- * Called when a device is exiting lock task mode by a package authorized
- * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+ * Called when a device is exiting lock task mode.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
@@ -488,6 +528,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
onLockTaskModeEntering(context, intent, pkg);
} else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
onLockTaskModeExiting(context, intent);
+ } else if (ACTION_READY_FOR_USER_INITIALIZATION.equals(action)) {
+ onReadyForUserInitialization(context, intent);
}
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 170224d..2c2328a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -28,6 +28,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.Handler;
@@ -108,7 +109,11 @@ public class DevicePolicyManager {
* Provisioning adds a managed profile and sets the MDM as the profile owner who has full
* control over the profile.
*
- * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+ * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this intent must contain the
+ * extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+ * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain the extra
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported.
*
* <p> When managed provisioning has completed, broadcasts are sent to the application specified
* in the provisioning intent. The
@@ -149,11 +154,36 @@ public class DevicePolicyManager {
*
* <p>This package is set as device owner when device owner provisioning is started by an NFC
* message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
+ *
+ * <p> When this extra is set, the application must have exactly one device admin receiver.
+ * This receiver will be set as the profile or device owner and active admin.</p>
+
+ * @see DeviceAdminReceiver
+ * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
+ * supported.
*/
+ @Deprecated
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
/**
+ * A ComponentName extra indicating the device admin receiver of the mobile device management
+ * application that will be set as the profile owner or device owner and active admin.
+ *
+ * <p>If an application starts provisioning directly via an intent with action
+ * {@link #ACTION_PROVISION_MANAGED_PROFILE} the package name of this component has to match the
+ * package name of the application that started provisioning.
+ *
+ * <p>This component is set as device owner and active admin when device owner provisioning is
+ * started by an NFC message containing an NFC record with MIME type
+ * {@link #MIME_TYPE_PROVISIONING_NFC}.
+ *
+ * @see DeviceAdminReceiver
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME
+ = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
+
+ /**
* An {@link android.accounts.Account} extra holding the account to migrate during managed
* profile provisioning. If the account supplied is present in the primary user, it will be
* copied, along with its credentials to the managed profile and removed from the primary user.
@@ -357,6 +387,52 @@ public class DevicePolicyManager {
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
/**
+ * On devices managed by a device owner app, a String representation of a Component name extra
+ * indicating the component of the application that is temporarily granted device owner
+ * privileges during device initialization and profile owner privileges during secondary user
+ * initialization.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ * @see ComponentName#unflattenFromString()
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+
+ /**
+ * A String extra holding an http url that specifies the download location of the device
+ * initializer package. When not provided it is assumed that the device initializer package is
+ * already installed.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
+
+ /**
+ * A String extra holding a http cookie header which should be used in the http request to the
+ * url specified in {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+
+ /**
+ * A String extra holding the SHA-1 checksum of the file at download location specified in
+ * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't
+ * match the file at the download location an error will be shown to the user and the user will
+ * be asked to factory reset the device.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+
+ /**
* This MIME type is used for starting the Device Owner provisioning.
*
* <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -372,7 +448,6 @@ public class DevicePolicyManager {
* <p>The NFC record must contain a serialized {@link java.util.Properties} object which
* contains the following properties:
* <ul>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li>
@@ -389,6 +464,15 @@ public class DevicePolicyManager {
* <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul>
*
+ * <p>
+ * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, it should also contain
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+ * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, (although
+ * specifying only {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
+ * This componentName must have been converted to a String via
+ * {@link android.content.ComponentName#flattenToString()}
+ *
* <p> When device owner provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
* device owner.
@@ -2382,6 +2466,113 @@ public class DevicePolicyManager {
}
/**
+ * Sets the given component as the device initializer. The package must already be installed and
+ * set as an active device administrator, and there must not be an existing device initializer,
+ * for this call to succeed. This method can only be called by an app holding the
+ * MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A
+ * device initializer app is granted device owner privileges during device initialization and
+ * profile owner privileges during secondary user initialization.
+ * @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not
+ * called by the device owner.
+ * @param initializer Which {@link DeviceAdminReceiver} to make device initializer.
+ * @param initializerName The user-visible name of the device initializer.
+ * @return whether the package was successfully registered as the device initializer.
+ * @throws IllegalArgumentException if the package name is null or invalid
+ * @throws IllegalStateException if the caller is not device owner or the device has
+ * already been provisioned or a device initializer already exists.
+ */
+ public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+ String initializerName) throws IllegalArgumentException, IllegalStateException {
+ if (mService != null) {
+ try {
+ return mService.setDeviceInitializer(who, initializer, initializerName);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to set device initializer");
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Used to determine if a particular package has been registered as the device initializer.
+ *
+ * @param packageName the package name of the app, to compare with the registered device
+ * initializer app, if any.
+ * @return whether or not the caller is registered as the device initializer app.
+ */
+ public boolean isDeviceInitializerApp(String packageName) {
+ if (mService != null) {
+ try {
+ return mService.isDeviceInitializer(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to check device initializer");
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the device initializer, so that it will not be invoked on user initialization for any
+ * subsequently created users. This method can be called by either the device owner or device
+ * initializer itself. The caller must be an active administrator.
+ *
+ * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+ */
+ public void clearDeviceInitializerApp(ComponentName who) {
+ if (mService != null) {
+ try {
+ mService.clearDeviceInitializer(who);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to clear device initializer");
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Gets the device initializer of the system.
+ *
+ * @return the package name of the device initializer.
+ */
+ @SystemApi
+ public String getDeviceInitializerApp() {
+ if (mService != null) {
+ try {
+ return mService.getDeviceInitializer();
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to get device initializer");
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the enabled state of the user. A user should be enabled only once it is ready to
+ * be used.
+ *
+ * <p>Device initializer must call this method to mark the user as functional.
+ * Only the device initializer agent can call this.
+ *
+ * <p>When the user is enabled, if the device initializer is not also the device owner, the
+ * device initializer will no longer have elevated permissions to call methods in this class.
+ * Additionally, it will be removed as an active administrator and its
+ * {@link DeviceAdminReceiver} will be disabled.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return whether the user is now enabled.
+ */
+ public boolean setUserEnabled(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.setUserEnabled(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return false;
+ }
+
+ /**
* @hide
* @deprecated Use #ACTION_SET_PROFILE_OWNER
* Sets the given component as an active admin and registers the package as the profile
@@ -3119,8 +3310,7 @@ public class DevicePolicyManager {
}
/**
- * Called by a profile or device owner to set a user restriction specified
- * by the key.
+ * Called by a profile or device owner to set a user restriction specified by the key.
* <p>
* The calling device admin must be a profile or device owner; if it is not,
* a security exception will be thrown.
@@ -3141,8 +3331,7 @@ public class DevicePolicyManager {
}
/**
- * Called by a profile or device owner to clear a user restriction specified
- * by the key.
+ * Called by a profile or device owner to clear a user restriction specified by the key.
* <p>
* The calling device admin must be a profile or device owner; if it is not,
* a security exception will be thrown.
@@ -3163,7 +3352,7 @@ public class DevicePolicyManager {
}
/**
- * Called by device or profile owner to hide or unhide packages. When a package is hidden it
+ * Called by profile or device owners to hide or unhide packages. When a package is hidden it
* is unavailable for use, but the data and actual package file remain.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3185,7 +3374,7 @@ public class DevicePolicyManager {
}
/**
- * Called by device or profile owner to determine if a package is hidden.
+ * Called by profile or device owners to determine if a package is hidden.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The name of the package to retrieve the hidden status of.
@@ -3203,7 +3392,7 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owner to re-enable a system app that was disabled by default
+ * Called by profile or device owners to re-enable a system app that was disabled by default
* when the user was initialized.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3220,7 +3409,7 @@ public class DevicePolicyManager {
}
/**
- * Called by profile or device owner to re-enable system apps by intent that were disabled
+ * Called by profile or device owners to re-enable system apps by intent that were disabled
* by default when the user was initialized.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3591,4 +3780,18 @@ public class DevicePolicyManager {
}
return Collections.emptyList();
}
+
+ /**
+ * Called by profile or device owners to set the current user's photo.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param icon the bitmap to set as the photo.
+ */
+ public void setUserIcon(ComponentName admin, Bitmap icon) {
+ try {
+ mService.setUserIcon(admin, icon);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not set the user icon ", re);
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 714e740..f69cf36 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@ package android.app.admin;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -199,4 +200,12 @@ interface IDevicePolicyManager {
boolean getAutoTimeRequired();
boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
+
+ boolean setUserEnabled(in ComponentName who);
+ boolean isDeviceInitializer(String packageName);
+ void clearDeviceInitializer(in ComponentName who);
+ boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName);
+ String getDeviceInitializer();
+
+ void setUserIcon(in ComponentName admin, in Bitmap icon);
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 1b1e600..7f89100 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -258,6 +258,7 @@ public abstract class BackupAgent extends ContextWrapper {
*
* <ul>
* <li>The contents of the {@link #getCacheDir()} directory</li>
+ * <li>The contents of the {@link #getCodeCacheDir()} directory</li>
* <li>The contents of the {@link #getNoBackupFilesDir()} directory</li>
* <li>The contents of the app's shared library directory</li>
* </ul>
@@ -285,6 +286,7 @@ public abstract class BackupAgent extends ContextWrapper {
String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
String cacheDir = getCacheDir().getCanonicalPath();
+ String codeCacheDir = getCodeCacheDir().getCanonicalPath();
String libDir = (appInfo.nativeLibraryDir != null)
? new File(appInfo.nativeLibraryDir).getCanonicalPath()
: null;
@@ -298,6 +300,7 @@ public abstract class BackupAgent extends ContextWrapper {
filterSet.add(libDir);
}
filterSet.add(cacheDir);
+ filterSet.add(codeCacheDir);
filterSet.add(databaseDir);
filterSet.add(sharedPrefsDir);
filterSet.add(filesDir);
@@ -354,6 +357,7 @@ public abstract class BackupAgent extends ContextWrapper {
String dbDir;
String spDir;
String cacheDir;
+ String codeCacheDir;
String libDir;
String efDir = null;
String filePath;
@@ -367,6 +371,7 @@ public abstract class BackupAgent extends ContextWrapper {
dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
cacheDir = getCacheDir().getCanonicalPath();
+ codeCacheDir = getCodeCacheDir().getCanonicalPath();
libDir = (appInfo.nativeLibraryDir == null)
? null
: new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -380,7 +385,8 @@ public abstract class BackupAgent extends ContextWrapper {
}
// Now figure out which well-defined tree the file is placed in, working from
- // most to least specific. We also specifically exclude the lib and cache dirs.
+ // most to least specific. We also specifically exclude the lib, cache,
+ // and code_cache dirs.
filePath = file.getCanonicalPath();
} catch (IOException e) {
Log.w(TAG, "Unable to obtain canonical paths");
@@ -388,9 +394,10 @@ public abstract class BackupAgent extends ContextWrapper {
}
if (filePath.startsWith(cacheDir)
+ || filePath.startsWith(codeCacheDir)
|| filePath.startsWith(libDir)
|| filePath.startsWith(nbFilesDir)) {
- Log.w(TAG, "lib, cache, and no_backup files are not backed up");
+ Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
return;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 010c860..61cdec3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.CheckResult;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -3041,6 +3042,7 @@ public abstract class Context {
* @see PackageManager#checkPermission(String, String)
* @see #checkCallingPermission
*/
+ @CheckResult(suggest="#enforcePermission(String,int,int,String)")
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
@@ -3070,6 +3072,7 @@ public abstract class Context {
* @see #checkPermission
* @see #checkCallingOrSelfPermission
*/
+ @CheckResult(suggest="#enforceCallingPermission(String,String)")
@PackageManager.PermissionResult
public abstract int checkCallingPermission(@NonNull String permission);
@@ -3089,6 +3092,7 @@ public abstract class Context {
* @see #checkPermission
* @see #checkCallingPermission
*/
+ @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)")
@PackageManager.PermissionResult
public abstract int checkCallingOrSelfPermission(@NonNull String permission);
@@ -3233,6 +3237,7 @@ public abstract class Context {
*
* @see #checkCallingUriPermission
*/
+ @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)")
public abstract int checkUriPermission(Uri uri, int pid, int uid,
@Intent.AccessUriMode int modeFlags);
@@ -3261,6 +3266,7 @@ public abstract class Context {
*
* @see #checkUriPermission(Uri, int, int, int)
*/
+ @CheckResult(suggest="#enforceCallingUriPermission(Uri,int,String)")
public abstract int checkCallingUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags);
/**
@@ -3280,6 +3286,7 @@ public abstract class Context {
*
* @see #checkCallingUriPermission
*/
+ @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)")
public abstract int checkCallingOrSelfUriPermission(Uri uri,
@Intent.AccessUriMode int modeFlags);
@@ -3305,6 +3312,7 @@ public abstract class Context {
* is allowed to access that uri or holds one of the given permissions, or
* {@link PackageManager#PERMISSION_DENIED} if it is not.
*/
+ @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)")
public abstract int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission,
@Nullable String writePermission, int pid, int uid,
@Intent.AccessUriMode int modeFlags);
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 8487dae..71a035e 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -20,7 +20,6 @@ import android.net.Uri;
import java.util.ArrayList;
import java.util.List;
-import java.util.regex.Pattern;
/**
Utility class to aid in matching URIs in content providers.
@@ -171,7 +170,7 @@ public class UriMatcher
if (path.length() > 0 && path.charAt(0) == '/') {
newPath = path.substring(1);
}
- tokens = PATH_SPLIT_PATTERN.split(newPath);
+ tokens = newPath.split("/");
}
int numTokens = tokens != null ? tokens.length : 0;
@@ -207,8 +206,6 @@ public class UriMatcher
node.mCode = code;
}
- static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/");
-
/**
* Try to match against the path in a url.
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ebc8e1e..0365689 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.CheckResult;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -2121,6 +2122,7 @@ public abstract class PackageManager {
* @see #PERMISSION_GRANTED
* @see #PERMISSION_DENIED
*/
+ @CheckResult
public abstract int checkPermission(String permName, String pkgName);
/**
@@ -2248,6 +2250,7 @@ public abstract class PackageManager {
* @see #SIGNATURE_NO_MATCH
* @see #SIGNATURE_UNKNOWN_PACKAGE
*/
+ @CheckResult
public abstract int checkSignatures(String pkg1, String pkg2);
/**
@@ -2270,6 +2273,7 @@ public abstract class PackageManager {
* @see #SIGNATURE_NO_MATCH
* @see #SIGNATURE_UNKNOWN_PACKAGE
*/
+ @CheckResult
public abstract int checkSignatures(int uid1, int uid2);
/**
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index ace402a..841b09d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources.Theme;
@@ -91,7 +92,7 @@ public class ColorStateList implements Parcelable {
* Creates a ColorStateList that returns the specified mapping from
* states to colors.
*/
- public ColorStateList(int[][] states, int[] colors) {
+ public ColorStateList(int[][] states, @ColorInt int[] colors) {
mStateSpecs = states;
mColors = colors;
@@ -102,7 +103,7 @@ public class ColorStateList implements Parcelable {
* @return A ColorStateList containing a single color.
*/
@NonNull
- public static ColorStateList valueOf(int color) {
+ public static ColorStateList valueOf(@ColorInt int color) {
synchronized (sCache) {
final int index = sCache.indexOfKey(color);
if (index >= 0) {
@@ -436,6 +437,7 @@ public class ColorStateList implements Parcelable {
*
* @return the default color in this {@link ColorStateList}.
*/
+ @ColorInt
public int getDefaultColor() {
return mDefaultColor;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 584f3f6..5dc9ef9 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.annotation.ColorInt;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -925,6 +926,7 @@ public class Resources {
* @return A single color value in the form 0xAARRGGBB.
* @deprecated Use {@link #getColor(int, Theme)} instead.
*/
+ @ColorInt
public int getColor(@ColorRes int id) throws NotFoundException {
return getColor(id, null);
}
@@ -945,6 +947,7 @@ public class Resources {
*
* @return A single color value in the form 0xAARRGGBB.
*/
+ @ColorInt
public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
TypedValue value;
synchronized (mAccessLock) {
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 3e07f0c..410849a 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -17,6 +17,7 @@
package android.content.res;
import android.annotation.AnyRes;
+import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
import android.os.StrictMode;
@@ -420,7 +421,8 @@ public class TypedArray {
* @throws UnsupportedOperationException if the attribute is defined but is
* not an integer color or color state list.
*/
- public int getColor(int index, int defValue) {
+ @ColorInt
+ public int getColor(int index, @ColorInt int defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index e1a2a25..e0d454c 100644
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -16,6 +16,7 @@
package android.gesture;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -204,18 +205,20 @@ public class GestureOverlayView extends FrameLayout {
mOrientation = orientation;
}
- public void setGestureColor(int color) {
+ public void setGestureColor(@ColorInt int color) {
mCertainGestureColor = color;
}
- public void setUncertainGestureColor(int color) {
+ public void setUncertainGestureColor(@ColorInt int color) {
mUncertainGestureColor = color;
}
+ @ColorInt
public int getUncertainGestureColor() {
return mUncertainGestureColor;
}
+ @ColorInt
public int getGestureColor() {
return mCertainGestureColor;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 43d3a71..0fee4b3 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -635,24 +635,34 @@ public abstract class BatteryStats implements Parcelable {
while (i < N && (c=value.charAt(i)) != '-') {
i++;
switch (c) {
- case 'f': out |= ((Display.STATE_OFF-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
- case 'o': out |= ((Display.STATE_ON-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
- case 'd': out |= ((Display.STATE_DOZE-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT); break;
- case 'z': out |= ((Display.STATE_DOZE_SUSPEND-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+ case 'f': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
break;
- case 'p': out |= (STEP_LEVEL_MODE_POWER_SAVE<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+ case 'o': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
break;
- case 'F': out |= ((Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
- case 'O': out |= ((Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
- case 'D': out |= ((Display.STATE_DOZE-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT); break;
- case 'Z': out |= ((Display.STATE_DOZE_SUSPEND-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ case 'd': out |= (((long)Display.STATE_DOZE-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
break;
- case 'P': out |= (STEP_LEVEL_MODE_POWER_SAVE<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ case 'z': out |= (((long)Display.STATE_DOZE_SUSPEND-1)
+ << STEP_LEVEL_INITIAL_MODE_SHIFT);
+ break;
+ case 'p': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
+ << STEP_LEVEL_INITIAL_MODE_SHIFT);
+ break;
+ case 'F': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
+ case 'O': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
+ case 'D': out |= (((long)Display.STATE_DOZE-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
+ case 'Z': out |= (((long)Display.STATE_DOZE_SUSPEND-1)
+ << STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
+ case 'P': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
+ << STEP_LEVEL_MODIFIED_MODE_SHIFT);
break;
}
}
i++;
- int level = 0;
+ long level = 0;
while (i < N && (c=value.charAt(i)) != '-') {
i++;
level <<= 4;
@@ -664,6 +674,7 @@ public abstract class BatteryStats implements Parcelable {
level += c - 'A' + 10;
}
}
+ i++;
out |= (level << STEP_LEVEL_LEVEL_SHIFT) & STEP_LEVEL_LEVEL_MASK;
long duration = 0;
while (i < N && (c=value.charAt(i)) != '-') {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d03365b..512e212 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -63,7 +63,10 @@ public final class Debug
*
* TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
* trace key file.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS;
/**
@@ -760,7 +763,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Stop counting the number and aggregate size of memory allocations.
*
- * @see #startAllocCounting()
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
@Deprecated
public static void stopAllocCounting() {
@@ -770,7 +773,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the global count of objects allocated by the runtime between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalAllocCount() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
}
@@ -778,7 +784,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the global count of objects allocated.
* @see #getGlobalAllocCount()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalAllocCount() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
}
@@ -786,7 +795,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the global size, in bytes, of objects allocated by the runtime between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalAllocSize() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
}
@@ -794,7 +806,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the global size of objects allocated.
* @see #getGlobalAllocSize()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalAllocSize() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
}
@@ -802,7 +817,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the global count of objects freed by the runtime between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalFreedCount() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
}
@@ -810,7 +828,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the global count of objects freed.
* @see #getGlobalFreedCount()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalFreedCount() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
}
@@ -818,7 +839,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the global size, in bytes, of objects freed by the runtime between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalFreedSize() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
}
@@ -826,7 +850,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the global size of objects freed.
* @see #getGlobalFreedSize()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalFreedSize() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
}
@@ -834,7 +861,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the number of non-concurrent GC invocations between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalGcInvocationCount() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
}
@@ -842,7 +872,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the count of non-concurrent GC invocations.
* @see #getGlobalGcInvocationCount()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalGcInvocationCount() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
}
@@ -851,7 +884,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* Returns the number of classes successfully initialized (ie those that executed without
* throwing an exception) between a {@link #startAllocCounting() start} and
* {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalClassInitCount() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
}
@@ -859,7 +895,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the count of classes initialized.
* @see #getGlobalClassInitCount()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalClassInitCount() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
}
@@ -867,7 +906,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the time spent successfully initializing classes between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getGlobalClassInitTime() {
/* cumulative elapsed time for class initialization, in usec */
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
@@ -876,7 +918,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the count of time spent initializing classes.
* @see #getGlobalClassInitTime()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetGlobalClassInitTime() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
}
@@ -948,7 +993,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the thread-local count of objects allocated by the runtime between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getThreadAllocCount() {
return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
}
@@ -956,7 +1004,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the thread-local count of objects allocated.
* @see #getThreadAllocCount()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetThreadAllocCount() {
VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
}
@@ -965,7 +1016,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* Returns the thread-local size of objects allocated by the runtime between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
* @return The allocated size in bytes.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getThreadAllocSize() {
return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
}
@@ -973,7 +1027,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the thread-local count of objects allocated.
* @see #getThreadAllocSize()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetThreadAllocSize() {
VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
}
@@ -1013,7 +1070,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Returns the number of thread-local non-concurrent GC invocations between a
* {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static int getThreadGcInvocationCount() {
return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
}
@@ -1021,7 +1081,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears the thread-local count of non-concurrent GC invocations.
* @see #getThreadGcInvocationCount()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetThreadGcInvocationCount() {
VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
}
@@ -1029,7 +1092,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Clears all the global and thread-local memory allocation counters.
* @see #startAllocCounting()
+ *
+ * @deprecated Accurate counting is a burden on the runtime and may be removed.
*/
+ @Deprecated
public static void resetAllCounts() {
VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 650f3b3..706e0d0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -391,6 +391,15 @@ public class UserManager {
public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
/**
+ * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
+ * is always set for managed profiles.
+ * @hide
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_WALLPAPER = "no_wallpaper";
+
+ /**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.
*
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 1b226c1..3d57b4d 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -17,6 +17,7 @@
package android.preference;
+import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.StringRes;
import android.app.AlertDialog;
@@ -360,6 +361,7 @@ public abstract class DialogPreference extends Preference implements
*
* @param view The content View of the dialog, if it is custom.
*/
+ @CallSuper
protected void onBindDialogView(View view) {
View dialogMessageView = view.findViewById(com.android.internal.R.id.message);
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 78928b2..ccf2cfa 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.annotation.CallSuper;
import com.android.internal.util.CharSequences;
import android.annotation.DrawableRes;
@@ -508,6 +509,7 @@ public class Preference implements Comparable<Preference> {
* @return The View that displays this Preference.
* @see #onBindView(View)
*/
+ @CallSuper
protected View onCreateView(ViewGroup parent) {
final LayoutInflater layoutInflater =
(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -537,6 +539,7 @@ public class Preference implements Comparable<Preference> {
* @param view The View that shows this Preference.
* @see #onCreateView(ViewGroup)
*/
+ @CallSuper
protected void onBindView(View view) {
final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title);
if (titleView != null) {
@@ -1356,6 +1359,7 @@ public class Preference implements Comparable<Preference> {
* should remove any references to this Preference that you know about. Make
* sure to call through to the superclass implementation.
*/
+ @CallSuper
protected void onPrepareForRemoval() {
unregisterDependency();
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 9cc12b5..cc7783f 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1010,7 +1010,8 @@ public final class ContactsContract {
/**
* Types of data used to produce the display name for a contact. In the order
* of increasing priority: {@link #EMAIL}, {@link #PHONE},
- * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}.
+ * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME},
+ * {@link #STRUCTURED_NAME}.
*/
public interface DisplayNameSources {
public static final int UNDEFINED = 0;
@@ -1018,6 +1019,8 @@ public final class ContactsContract {
public static final int PHONE = 20;
public static final int ORGANIZATION = 30;
public static final int NICKNAME = 35;
+ /** Display name comes from a structured name that only has phonetic components. */
+ public static final int STRUCTURED_PHONETIC_NAME = 37;
public static final int STRUCTURED_NAME = 40;
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 1316471..6979bee 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -28,6 +28,7 @@ import static android.provider.DocumentsContract.getSearchDocumentsQuery;
import static android.provider.DocumentsContract.getTreeDocumentId;
import static android.provider.DocumentsContract.isTreeUri;
+import android.annotation.CallSuper;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -541,6 +542,7 @@ public abstract class DocumentsProvider extends ContentProvider {
*
* @see DocumentsContract#buildDocumentUriUsingTree(Uri, String)
*/
+ @CallSuper
@Override
public Uri canonicalize(Uri uri) {
final Context context = getContext();
@@ -616,6 +618,7 @@ public abstract class DocumentsProvider extends ContentProvider {
* call the superclass. If the superclass returns {@code null}, the subclass
* may implement custom behavior.
*/
+ @CallSuper
@Override
public Bundle call(String method, String arg, Bundle extras) {
if (!method.startsWith("android:")) {
diff --git a/core/java/android/service/chooser/ChooserTarget.aidl b/core/java/android/service/chooser/ChooserTarget.aidl
new file mode 100644
index 0000000..ca91bc8
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTarget.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.chooser;
+
+parcelable ChooserTarget;
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
new file mode 100644
index 0000000..7fd1d10
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.service.chooser;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A ChooserTarget represents a deep-link into an application as returned by a
+ * {@link android.service.chooser.ChooserTargetService}.
+ */
+public final class ChooserTarget implements Parcelable {
+ private static final String TAG = "ChooserTarget";
+
+ /**
+ * The title of this target that will be shown to the user. The title may be truncated
+ * if it is too long to display in the space provided.
+ */
+ private CharSequence mTitle;
+
+ /**
+ * The icon that will be shown to the user to represent this target.
+ * The system may resize this icon as appropriate.
+ */
+ private Bitmap mIcon;
+
+ /**
+ * The IntentSender that will be used to deliver the intent to the target.
+ * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in}
+ * by the real intent sent by the application.
+ */
+ private IntentSender mIntentSender;
+
+ /**
+ * The score given to this item. It can be normalized.
+ */
+ private float mScore;
+
+ /**
+ * Construct a deep link target for presentation by a chooser UI.
+ *
+ * <p>A target is composed of a title and an icon for presentation to the user.
+ * The UI presenting this target may truncate the title if it is too long to be presented
+ * in the available space, as well as crop, resize or overlay the supplied icon.</p>
+ *
+ * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
+ * to the other targets supplied by the same
+ * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
+ * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).</p>
+ *
+ * <p>Before being sent, the PendingIntent supplied will be
+ * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
+ * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure
+ * that you permit the relevant fields to be filled in using the appropriate flags such as
+ * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
+ * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
+ * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
+ * for {@link Intent#ACTION_SEND} intents.</p>
+ *
+ * <p>Take care not to place custom {@link android.os.Parcelable} types into
+ * the PendingIntent as extras, as the system will not be able to unparcel it to merge
+ * additional extras.</p>
+ *
+ * @param title title of this target that will be shown to a user
+ * @param icon icon to represent this target
+ * @param score ranking score for this target between 0.0f and 1.0f, inclusive
+ * @param pendingIntent PendingIntent to fill in and send if the user chooses this target
+ */
+ public ChooserTarget(CharSequence title, Bitmap icon, float score,
+ PendingIntent pendingIntent) {
+ this(title, icon, score, pendingIntent.getIntentSender());
+ }
+
+ /**
+ * Construct a deep link target for presentation by a chooser UI.
+ *
+ * <p>A target is composed of a title and an icon for presentation to the user.
+ * The UI presenting this target may truncate the title if it is too long to be presented
+ * in the available space, as well as crop, resize or overlay the supplied icon.</p>
+ *
+ * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
+ * to the other targets supplied by the same
+ * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
+ * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).</p>
+ *
+ * <p>Before being sent, the IntentSender supplied will be
+ * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
+ * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure
+ * that you permit the relevant fields to be filled in using the appropriate flags such as
+ * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
+ * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
+ * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
+ * for {@link Intent#ACTION_SEND} intents.</p>
+ *
+ * <p>Take care not to place custom {@link android.os.Parcelable} types into
+ * the IntentSender as extras, as the system will not be able to unparcel it to merge
+ * additional extras.</p>
+ *
+ * @param title title of this target that will be shown to a user
+ * @param icon icon to represent this target
+ * @param score ranking score for this target between 0.0f and 1.0f, inclusive
+ * @param intentSender IntentSender to fill in and send if the user chooses this target
+ */
+ public ChooserTarget(CharSequence title, Bitmap icon, float score, IntentSender intentSender) {
+ mTitle = title;
+ mIcon = icon;
+ if (score > 1.f || score < 0.f) {
+ throw new IllegalArgumentException("Score " + score + " out of range; "
+ + "must be between 0.0f and 1.0f");
+ }
+ mScore = score;
+ mIntentSender = intentSender;
+ }
+
+ ChooserTarget(Parcel in) {
+ mTitle = in.readCharSequence();
+ if (in.readInt() != 0) {
+ mIcon = Bitmap.CREATOR.createFromParcel(in);
+ } else {
+ mIcon = null;
+ }
+ mScore = in.readFloat();
+ mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+ }
+
+ /**
+ * Returns the title of this target for display to a user. The UI displaying the title
+ * may truncate this title if it is too long to be displayed in full.
+ *
+ * @return the title of this target, intended to be shown to a user
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Returns the icon representing this target for display to a user. The UI displaying the icon
+ * may crop, resize or overlay this icon.
+ *
+ * @return the icon representing this target, intended to be shown to a user
+ */
+ public Bitmap getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * Returns the ranking score supplied by the creator of this ChooserTarget.
+ * Values are between 0.0f and 1.0f. The UI displaying the target may
+ * take this score into account when sorting and merging targets from multiple sources.
+ *
+ * @return the ranking score for this target between 0.0f and 1.0f, inclusive
+ */
+ public float getScore() {
+ return mScore;
+ }
+
+ /**
+ * Returns the raw IntentSender supplied by the ChooserTarget's creator.
+ *
+ * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
+ *
+ * @return the IntentSender supplied by the ChooserTarget's creator
+ */
+ public IntentSender getIntentSender() {
+ return mIntentSender;
+ }
+
+ /**
+ * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
+ *
+ * @param context the sending Context; generally the Activity presenting the chooser UI
+ * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target
+ * @return true if sending the Intent was successful
+ */
+ public boolean sendIntent(Context context, Intent fillInIntent) {
+ if (fillInIntent != null) {
+ fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.prepareToLeaveProcess();
+ }
+ try {
+ mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
+ return true;
+ } catch (IntentSender.SendIntentException e) {
+ Log.e(TAG, "sendIntent " + this + " failed", e);
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ChooserTarget{" + mIntentSender.getCreatorPackage() + "'" + mTitle
+ + "', " + mScore + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mTitle);
+ if (mIcon != null) {
+ dest.writeInt(1);
+ mIcon.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeFloat(mScore);
+ IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
+ }
+
+ public static final Creator<ChooserTarget> CREATOR
+ = new Creator<ChooserTarget>() {
+ @Override
+ public ChooserTarget createFromParcel(Parcel source) {
+ return new ChooserTarget(source);
+ }
+
+ @Override
+ public ChooserTarget[] newArray(int size) {
+ return new ChooserTarget[size];
+ }
+ };
+}
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
new file mode 100644
index 0000000..9188806
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.service.chooser;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A service that receives calls from the system when the user is asked to choose
+ * a target for an intent explicitly by another app. The calling app must have invoked
+ * {@link android.content.Intent#ACTION_CHOOSER ACTION_CHOOSER} as handled by the system;
+ * applications do not have the ability to query a ChooserTargetService directly.
+ *
+ * <p>Which ChooserTargetServices are queried depends on a system-level policy decision
+ * made at the moment the chooser is invoked, including but not limited to user time
+ * spent with the app package or associated components in the foreground, recency of usage
+ * or frequency of usage. These will generally correlate with the order that app targets
+ * are shown in the list of intent handlers shown in the system chooser or resolver.</p>
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CHOOSER_TARGET_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * &lt;service android:name=".ChooserTargetService"
+ * android:label="&#64;string/service_name"
+ * android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
+ * &lt;intent-filter>
+ * &lt;action android:name="android.service.chooser.ChooserTargetService" />
+ * &lt;/intent-filter>
+ * &lt;/service>
+ * </pre>
+ *
+ * <p>For the system to query your service, you must add a &lt;meta-data> element to the
+ * Activity in your manifest that can handle Intents that you would also like to provide
+ * optional deep links for. For example, a chat app might offer deep links to recent active
+ * conversations instead of invoking a generic picker after the app itself is chosen as a target.
+ * </p>
+ *
+ * <p>The meta-data element should have the name
+ * <code>android.service.chooser.chooser_target_service</code> and a value corresponding to
+ * the component name of your service. Example:</p>
+ * <pre>
+ * &lt;activity android:name=".MyShareActivity"
+ * android:label="&#64;string/share_activity_label">
+ * &lt;intent-filter>
+ * &lt;action android:name="android.intent.action.SEND" />
+ * &lt;/intent-filter>
+ * &lt;meta-data android:name="android.service.chooser.chooser_target_service"
+ * android:value=".ChooserTargetService" />
+ * &lt;/activity>
+ * </pre>
+ */
+public abstract class ChooserTargetService extends Service {
+ // TAG = "ChooserTargetService[MySubclass]";
+ private final String TAG = ChooserTargetService.class.getSimpleName()
+ + '[' + getClass().getSimpleName() + ']';
+
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+
+ private IChooserTargetServiceWrapper mWrapper = null;
+
+ /**
+ * Called by the system to retrieve a set of deep-link {@link ChooserTarget targets} that
+ * can handle an intent.
+ *
+ * <p>The returned list should be sorted such that the most relevant targets appear first.
+ * Any PendingIntents used to construct the resulting ChooserTargets should always be prepared
+ * to have the relevant data fields filled in by the sender. See
+ * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent) ChooserTarget}.</p>
+ *
+ * <p><em>Important:</em> Calls to this method from other applications will occur on
+ * a binder thread, not on your app's main thread. Make sure that access to relevant data
+ * within your app is thread-safe.</p>
+ *
+ * @param targetActivityName the ComponentName of the matched activity that referred the system
+ * to this ChooserTargetService
+ * @param matchedFilter the specific IntentFilter on the component that was matched
+ * @return a list of deep-link targets to fulfill the intent match, sorted by relevance
+ */
+ public abstract List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName,
+ IntentFilter matchedFilter);
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+ return null;
+ }
+
+ if (mWrapper == null) {
+ mWrapper = new IChooserTargetServiceWrapper();
+ }
+ return mWrapper;
+ }
+
+ private class IChooserTargetServiceWrapper extends IChooserTargetService.Stub {
+ @Override
+ public void getChooserTargets(ComponentName targetComponentName,
+ IntentFilter matchedFilter, IChooserTargetResult result) throws RemoteException {
+ List<ChooserTarget> targets = null;
+ try {
+ targets = onGetChooserTargets(targetComponentName, matchedFilter);
+ } finally {
+ result.sendResult(targets);
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/chooser/IChooserTargetResult.aidl b/core/java/android/service/chooser/IChooserTargetResult.aidl
new file mode 100644
index 0000000..dbd7cbd
--- /dev/null
+++ b/core/java/android/service/chooser/IChooserTargetResult.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.chooser;
+
+import android.service.chooser.ChooserTarget;
+
+/**
+ * @hide
+ */
+interface IChooserTargetResult
+{
+ void sendResult(in List<ChooserTarget> targets);
+}
diff --git a/core/java/android/service/chooser/IChooserTargetService.aidl b/core/java/android/service/chooser/IChooserTargetService.aidl
new file mode 100644
index 0000000..6cfa9a2
--- /dev/null
+++ b/core/java/android/service/chooser/IChooserTargetService.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.chooser;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.service.chooser.IChooserTargetResult;
+
+/**
+ * @hide
+ */
+oneway interface IChooserTargetService
+{
+ void getChooserTargets(in ComponentName targetComponentName,
+ in IntentFilter matchedFilter, IChooserTargetResult result);
+} \ No newline at end of file
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 77ef1da..1bdaef0 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -270,22 +270,30 @@ public class DynamicLayout extends Layout
// generate new layout for affected text
StaticLayout reflowed;
+ StaticLayout.Builder b;
synchronized (sLock) {
reflowed = sStaticLayout;
+ b = sBuilder;
sStaticLayout = null;
+ sBuilder = null;
}
+ // TODO: make sure reflowed is properly initialized
if (reflowed == null) {
reflowed = new StaticLayout(null);
- } else {
- reflowed.prepare();
- }
-
- reflowed.generate(text, where, where + after,
- getPaint(), getWidth(), getTextDirectionHeuristic(), getSpacingMultiplier(),
- getSpacingAdd(), false,
- true, mEllipsizedWidth, mEllipsizeAt);
+ b = StaticLayout.Builder.obtain();
+ }
+
+ b.setText(text, where, where + after)
+ .setPaint(getPaint())
+ .setWidth(getWidth())
+ .setTextDir(getTextDirectionHeuristic())
+ .setSpacingMult(getSpacingMultiplier())
+ .setSpacingAdd(getSpacingAdd())
+ .setEllipsizedWidth(mEllipsizedWidth)
+ .setEllipsize(mEllipsizeAt);
+ reflowed.generate(b, false, true);
int n = reflowed.getLineCount();
// If the new layout has a blank line at the end, but it is not
@@ -359,9 +367,10 @@ public class DynamicLayout extends Layout
updateBlocks(startline, endline - 1, n);
+ b.finish();
synchronized (sLock) {
sStaticLayout = reflowed;
- reflowed.finish();
+ sBuilder = b;
}
}
@@ -720,7 +729,8 @@ public class DynamicLayout extends Layout
private int mTopPadding, mBottomPadding;
- private static StaticLayout sStaticLayout = new StaticLayout(null);
+ private static StaticLayout sStaticLayout = null;
+ private static StaticLayout.Builder sBuilder = null;
private static final Object[] sLock = new Object[0];
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index e72e18f..832002c 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -66,21 +66,28 @@ class MeasuredText {
}
static MeasuredText recycle(MeasuredText mt) {
- mt.mText = null;
- if (mt.mLen < 1000) {
- synchronized(sLock) {
- for (int i = 0; i < sCached.length; ++i) {
- if (sCached[i] == null) {
- sCached[i] = mt;
- mt.mText = null;
- break;
- }
+ mt.finish();
+ synchronized(sLock) {
+ for (int i = 0; i < sCached.length; ++i) {
+ if (sCached[i] == null) {
+ sCached[i] = mt;
+ mt.mText = null;
+ break;
}
}
}
return null;
}
+ void finish() {
+ mText = null;
+ if (mLen > 1000) {
+ mWidths = null;
+ mChars = null;
+ mLevels = null;
+ }
+ }
+
void setPos(int pos) {
mPos = pos - mTextStart;
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ffb7d36..967e80c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -28,6 +28,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import java.util.Arrays;
+import java.util.Locale;
/**
* StaticLayout is a Layout for text that will not be edited after it
@@ -43,6 +44,179 @@ public class StaticLayout extends Layout {
static final String TAG = "StaticLayout";
+ /**
+ * Builder for static layouts. It would be better if this were a public
+ * API (as it would offer much greater flexibility for adding new options)
+ * but for the time being it's just internal.
+ *
+ * @hide
+ */
+ public final static class Builder {
+ private Builder() {
+ mNativePtr = nNewBuilder();
+ }
+
+ static Builder obtain() {
+ Builder b = null;
+ synchronized (sLock) {
+ for (int i = 0; i < sCached.length; i++) {
+ if (sCached[i] != null) {
+ b = sCached[i];
+ sCached[i] = null;
+ break;
+ }
+ }
+ }
+ if (b == null) {
+ b = new Builder();
+ }
+
+ // set default initial values
+ b.mWidth = 0;
+ b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
+ b.mSpacingMult = 1.0f;
+ b.mSpacingAdd = 0.0f;
+ b.mIncludePad = true;
+ b.mEllipsizedWidth = 0;
+ b.mEllipsize = null;
+ b.mMaxLines = Integer.MAX_VALUE;
+
+ b.mMeasuredText = MeasuredText.obtain();
+ return b;
+ }
+
+ static void recycle(Builder b) {
+ b.mPaint = null;
+ b.mText = null;
+ MeasuredText.recycle(b.mMeasuredText);
+ synchronized (sLock) {
+ for (int i = 0; i < sCached.length; i++) {
+ if (sCached[i] == null) {
+ sCached[i] = b;
+ break;
+ }
+ }
+ }
+ }
+
+ // release any expensive state
+ /* package */ void finish() {
+ nFinishBuilder(mNativePtr);
+ mMeasuredText.finish();
+ }
+
+ public Builder setText(CharSequence source) {
+ return setText(source, 0, source.length());
+ }
+
+ public Builder setText(CharSequence source, int start, int end) {
+ mText = source;
+ mStart = start;
+ mEnd = end;
+ return this;
+ }
+
+ public Builder setPaint(TextPaint paint) {
+ mPaint = paint;
+ return this;
+ }
+
+ public Builder setWidth(int width) {
+ mWidth = width;
+ if (mEllipsize == null) {
+ mEllipsizedWidth = width;
+ }
+ return this;
+ }
+
+ public Builder setTextDir(TextDirectionHeuristic textDir) {
+ mTextDir = textDir;
+ return this;
+ }
+
+ // TODO: combine the following, as they're almost always set together?
+ public Builder setSpacingMult(float spacingMult) {
+ mSpacingMult = spacingMult;
+ return this;
+ }
+
+ public Builder setSpacingAdd(float spacingAdd) {
+ mSpacingAdd = spacingAdd;
+ return this;
+ }
+
+ public Builder setIncludePad(boolean includePad) {
+ mIncludePad = includePad;
+ return this;
+ }
+
+ // TODO: combine the following?
+ public Builder setEllipsizedWidth(int ellipsizedWidth) {
+ mEllipsizedWidth = ellipsizedWidth;
+ return this;
+ }
+
+ public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
+ mEllipsize = ellipsize;
+ return this;
+ }
+
+ public Builder setMaxLines(int maxLines) {
+ mMaxLines = maxLines;
+ return this;
+ }
+
+ /* @hide */
+ public void setLocale(Locale locale) {
+ if (!locale.equals(mLocale)) {
+ nBuilderSetLocale(mNativePtr, locale.toLanguageTag());
+ mLocale = locale;
+ }
+ }
+
+ public StaticLayout build() {
+ // TODO: can optimize based on whether ellipsis is needed
+ StaticLayout result = new StaticLayout(mText);
+ result.initFromBuilder(this);
+ recycle(this);
+ return result;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nFreeBuilder(mNativePtr);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /* package */ long mNativePtr;
+
+ CharSequence mText;
+ int mStart;
+ int mEnd;
+ TextPaint mPaint;
+ int mWidth;
+ TextDirectionHeuristic mTextDir;
+ float mSpacingMult;
+ float mSpacingAdd;
+ boolean mIncludePad;
+ int mEllipsizedWidth;
+ TextUtils.TruncateAt mEllipsize;
+ int mMaxLines;
+
+ Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
+
+ // This will go away and be subsumed by native builder code
+ MeasuredText mMeasuredText;
+
+ Locale mLocale;
+
+ private static final Object sLock = new Object();
+ private static final Builder[] sCached = new Builder[3];
+ }
+
public StaticLayout(CharSequence source, TextPaint paint,
int width,
Alignment align, float spacingmult, float spacingadd,
@@ -110,6 +284,17 @@ public class StaticLayout extends Layout {
: new Ellipsizer(source),
paint, outerwidth, align, textDir, spacingmult, spacingadd);
+ Builder b = Builder.obtain();
+ b.setText(source, bufstart, bufend)
+ .setPaint(paint)
+ .setWidth(outerwidth)
+ .setTextDir(textDir)
+ .setSpacingMult(spacingmult)
+ .setSpacingAdd(spacingadd)
+ .setIncludePad(includepad)
+ .setEllipsizedWidth(ellipsizedWidth)
+ .setEllipsize(ellipsize)
+ .setMaxLines(maxLines);
/*
* This is annoying, but we can't refer to the layout until
* superclass construction is finished, and the superclass
@@ -136,14 +321,9 @@ public class StaticLayout extends Layout {
mLines = new int[mLineDirections.length];
mMaximumVisibleLineCount = maxLines;
- mMeasured = MeasuredText.obtain();
-
- generate(source, bufstart, bufend, paint, outerwidth, textDir, spacingmult,
- spacingadd, includepad, includepad, ellipsizedWidth,
- ellipsize);
+ initFromBuilder(b);
- mMeasured = MeasuredText.recycle(mMeasured);
- mFontMetricsInt = null;
+ Builder.recycle(b);
}
/* package */ StaticLayout(CharSequence text) {
@@ -152,33 +332,40 @@ public class StaticLayout extends Layout {
mColumns = COLUMNS_ELLIPSIZE;
mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
mLines = new int[mLineDirections.length];
- // FIXME This is never recycled
- mMeasured = MeasuredText.obtain();
}
- /* package */ void generate(CharSequence source, int bufStart, int bufEnd,
- TextPaint paint, int outerWidth,
- TextDirectionHeuristic textDir, float spacingmult,
- float spacingadd, boolean includepad,
- boolean trackpad, float ellipsizedWidth,
- TextUtils.TruncateAt ellipsize) {
- LineBreaks lineBreaks = new LineBreaks();
+ private void initFromBuilder(Builder b) {
+ generate(b, b.mIncludePad, b.mIncludePad);
+ }
+
+ /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
+ CharSequence source = b.mText;
+ int bufStart = b.mStart;
+ int bufEnd = b.mEnd;
+ TextPaint paint = b.mPaint;
+ int outerWidth = b.mWidth;
+ TextDirectionHeuristic textDir = b.mTextDir;
+ float spacingmult = b.mSpacingMult;
+ float spacingadd = b.mSpacingAdd;
+ float ellipsizedWidth = b.mEllipsizedWidth;
+ TextUtils.TruncateAt ellipsize = b.mEllipsize;
+ LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs
// store span end locations
int[] spanEndCache = new int[4];
// store fontMetrics per span range
// must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
int[] fmCache = new int[4 * 4];
- final String localeLanguageTag = paint.getTextLocale().toLanguageTag();
+ b.setLocale(paint.getTextLocale()); // TODO: also respect LocaleSpan within the text
mLineCount = 0;
int v = 0;
boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
- Paint.FontMetricsInt fm = mFontMetricsInt;
+ Paint.FontMetricsInt fm = b.mFontMetricsInt;
int[] chooseHtv = null;
- MeasuredText measured = mMeasured;
+ MeasuredText measured = b.mMeasuredText;
Spanned spanned = null;
if (source instanceof Spanned)
@@ -306,7 +493,7 @@ public class StaticLayout extends Layout {
}
}
- int breakCount = nComputeLineBreaks(localeLanguageTag, chs, widths, paraEnd - paraStart, firstWidth,
+ int breakCount = nComputeLineBreaks(b.mNativePtr, chs, widths, paraEnd - paraStart, firstWidth,
firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
@@ -746,24 +933,21 @@ public class StaticLayout extends Layout {
return mEllipsizedWidth;
}
- void prepare() {
- mMeasured = MeasuredText.obtain();
- }
-
- void finish() {
- mMeasured = MeasuredText.recycle(mMeasured);
- }
-
// populates LineBreaks and returns the number of breaks found
//
// the arrays inside the LineBreaks objects are passed in as well
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
- private static native int nComputeLineBreaks(String locale, char[] text, float[] widths,
+ private static native int nComputeLineBreaks(long nativePtr, char[] text, float[] widths,
int length, float firstWidth, int firstWidthLineCount, float restWidth,
int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
+ private static native long nNewBuilder();
+ private static native void nFreeBuilder(long nativePtr);
+ private static native void nFinishBuilder(long nativePtr);
+ private static native void nBuilderSetLocale(long nativePtr, String locale);
+
private int mLineCount;
private int mTopPadding, mBottomPadding;
private int mColumns;
@@ -793,12 +977,6 @@ public class StaticLayout extends Layout {
private static final double EXTRA_ROUNDING = 0.5;
- /*
- * This is reused across calls to generate()
- */
- private MeasuredText mMeasured;
- private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
-
// This is used to return three arrays from a single JNI call when
// performing line breaking
/*package*/ static class LineBreaks {
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index 0447117..4f8cff0 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.ColorInt;
import android.graphics.Paint;
/**
@@ -25,8 +26,10 @@ import android.graphics.Paint;
public class TextPaint extends Paint {
// Special value 0 means no background paint
+ @ColorInt
public int bgColor;
public int baselineShift;
+ @ColorInt
public int linkColor;
public int[] drawableState;
public float density = 1.0f;
@@ -34,6 +37,7 @@ public class TextPaint extends Paint {
* Special value 0 means no custom underline
* @hide
*/
+ @ColorInt
public int underlineColor = 0;
/**
* Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index c9e09bd..f167aab 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.annotation.ColorInt;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
@@ -26,7 +27,7 @@ public class ForegroundColorSpan extends CharacterStyle
private final int mColor;
- public ForegroundColorSpan(int color) {
+ public ForegroundColorSpan(@ColorInt int color) {
mColor = color;
}
@@ -46,6 +47,7 @@ public class ForegroundColorSpan extends CharacterStyle
dest.writeInt(mColor);
}
+ @ColorInt
public int getForegroundColor() {
return mColor;
}
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 29dd273..17748ca 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.annotation.ColorInt;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.os.Parcel;
@@ -34,7 +35,7 @@ public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan {
mColor = 0xff0000ff;
}
- public QuoteSpan(int color) {
+ public QuoteSpan(@ColorInt int color) {
super();
mColor = color;
}
@@ -55,6 +56,7 @@ public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan {
dest.writeInt(mColor);
}
+ @ColorInt
public int getColor() {
return mColor;
}
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 68f725e..7da3941 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -475,6 +475,26 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
}
/**
+ * Perform a {@link #remove(Object)} of all values in <var>array</var>
+ * @param array The array whose contents are to be removed.
+ */
+ public boolean removeAll(ArraySet<? extends E> array) {
+ // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
+ // pass, use the property that the sets are sorted by hash to make this linear passes
+ // (except for hash collisions, which means worst case still n*m), then do one
+ // collection pass into a new array. This avoids binary searches and excessive memcpy.
+ final int N = array.mSize;
+
+ // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
+ // the single results, compare size before and after.
+ final int originalSize = mSize;
+ for (int i = 0; i < N; i++) {
+ remove(array.valueAt(i));
+ }
+ return originalSize != mSize;
+ }
+
+ /**
* Return the number of items in this array map.
*/
@Override
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index f607207..84d9ce8 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -16,6 +16,7 @@
package android.util;
+import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;
@@ -123,4 +124,83 @@ public class DebugUtils {
}
}
+ /** @hide */
+ public static void printSizeValue(PrintWriter pw, long number) {
+ float result = number;
+ String suffix = "";
+ if (result > 900) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ value = String.format("%.1f", result);
+ } else if (result < 100) {
+ value = String.format("%.0f", result);
+ } else {
+ value = String.format("%.0f", result);
+ }
+ pw.print(value);
+ pw.print(suffix);
+ }
+
+ /** @hide */
+ public static String sizeValueToString(long number, StringBuilder outBuilder) {
+ if (outBuilder == null) {
+ outBuilder = new StringBuilder(32);
+ }
+ float result = number;
+ String suffix = "";
+ if (result > 900) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ value = String.format("%.1f", result);
+ } else if (result < 100) {
+ value = String.format("%.0f", result);
+ } else {
+ value = String.format("%.0f", result);
+ }
+ outBuilder.append(value);
+ outBuilder.append(suffix);
+ return outBuilder.toString();
+ }
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 0d36949..06e196d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -204,7 +204,7 @@ class GLES20Canvas extends HardwareCanvas {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk,
+ nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@@ -214,7 +214,7 @@ class GLES20Canvas extends HardwareCanvas {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap.mNativeBitmap, patch.mNativeChunk,
+ nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index df0838f..69b4c47 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -364,7 +364,7 @@ public class ThreadedRenderer extends HardwareRenderer {
@Override
boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
return nCopyLayerInto(mNativeProxy,
- layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+ layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
}
@Override
@@ -465,7 +465,7 @@ public class ThreadedRenderer extends HardwareRenderer {
for (int i = 0; i < count; i++) {
drawables.valueAt(i).addAtlasableBitmaps(tmpList);
for (int j = 0; j < tmpList.size(); j++) {
- preloadedPointers.add(tmpList.get(j).mNativeBitmap);
+ preloadedPointers.add(tmpList.get(j).getSkBitmap());
}
tmpList.clear();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f25b640..7d49969 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,11 +18,15 @@ package android.view;
import android.animation.AnimatorInflater;
import android.animation.StateListAnimator;
+import android.annotation.CallSuper;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.FloatRange;
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Size;
import android.content.ClipData;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -5148,6 +5152,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* passed in as finer grained information about where the focus is coming
* from (in addition to direction). Will be <code>null</code> otherwise.
*/
+ @CallSuper
protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
@Nullable Rect previouslyFocusedRect) {
if (gainFocus) {
@@ -5370,6 +5375,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #sendAccessibilityEvent(int)
* @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
*/
+ @CallSuper
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
if (mAccessibilityDelegate != null) {
mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
@@ -5414,6 +5420,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #sendAccessibilityEvent(int)
* @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
*/
+ @CallSuper
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
if (mAccessibilityDelegate != null) {
mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
@@ -5528,6 +5535,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param info The instance to initialize.
*/
+ @CallSuper
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
if (mAccessibilityDelegate != null) {
mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
@@ -5849,7 +5857,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see AccessibilityDelegate
*/
- public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+ public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
mAccessibilityDelegate = delegate;
}
@@ -6089,6 +6097,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide pending API council approval
*/
+ @CallSuper
protected void onFocusLost() {
resetPressedState();
}
@@ -10573,7 +10582,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_alpha
*/
- public void setAlpha(float alpha) {
+ public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
mTransformationInfo.mAlpha = alpha;
@@ -13425,6 +13434,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide
*/
+ @CallSuper
protected void onDetachedFromWindowInternal() {
mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
@@ -14039,6 +14049,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @hide
*/
+ @CallSuper
protected void destroyHardwareResources() {
// Although the Layer will be destroyed by RenderNode, we want to release
// the staging display list, which is also a signal to RenderNode that it's
@@ -14311,7 +14322,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #buildDrawingCache()
* @see #getDrawingCache()
*/
- public void setDrawingCacheBackgroundColor(int color) {
+ public void setDrawingCacheBackgroundColor(@ColorInt int color) {
if (color != mDrawingCacheBackgroundColor) {
mDrawingCacheBackgroundColor = color;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
@@ -14323,6 +14334,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return The background color to used for the drawing cache's bitmap
*/
+ @ColorInt
public int getDrawingCacheBackgroundColor() {
return mDrawingCacheBackgroundColor;
}
@@ -15227,6 +15239,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param canvas The Canvas to which the View is rendered.
*/
+ @CallSuper
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
@@ -15536,6 +15549,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The known solid color background for this view, or 0 if the color may vary
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @ColorInt
public int getSolidColor() {
return 0;
}
@@ -15828,6 +15842,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <p>Even if the subclass overrides onFinishInflate, they should always be
* sure to call the super method, so that we get called.
*/
+ @CallSuper
protected void onFinishInflate() {
}
@@ -15993,6 +16008,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #unscheduleDrawable(android.graphics.drawable.Drawable)
* @see #drawableStateChanged()
*/
+ @CallSuper
protected boolean verifyDrawable(Drawable who) {
return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who);
}
@@ -16008,6 +16024,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see Drawable#setState(int[])
*/
+ @CallSuper
protected void drawableStateChanged() {
final int[] state = getDrawableState();
@@ -16040,6 +16057,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param x hotspot x coordinate
* @param y hotspot y coordinate
*/
+ @CallSuper
public void drawableHotspotChanged(float x, float y) {
if (mBackground != null) {
mBackground.setHotspot(x, y);
@@ -16222,7 +16240,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param color the color of the background
*/
@RemotableViewMethod
- public void setBackgroundColor(int color) {
+ public void setBackgroundColor(@ColorInt int color) {
if (mBackground instanceof ColorDrawable) {
((ColorDrawable) mBackground.mutate()).setColor(color);
computeOpaqueFlags();
@@ -16238,6 +16256,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return The color of the ColorDrawable background, if set, otherwise 0.
*/
+ @ColorInt
public int getBackgroundColor() {
if (mBackground instanceof ColorDrawable) {
return ((ColorDrawable) mBackground).getColor();
@@ -17011,7 +17030,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param location an array of two integers in which to hold the coordinates
*/
- public void getLocationOnScreen(int[] location) {
+ public void getLocationOnScreen(@Size(2) int[] location) {
getLocationInWindow(location);
final AttachInfo info = mAttachInfo;
@@ -17028,7 +17047,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @param location an array of two integers in which to hold the coordinates
*/
- public void getLocationInWindow(int[] location) {
+ public void getLocationInWindow(@Size(2) int[] location) {
if (location == null || location.length < 2) {
throw new IllegalArgumentException("location must be an array of two integers");
}
@@ -17512,6 +17531,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <p>Subclasses which override this method should call the superclass method to
* handle possible request-during-layout errors correctly.</p>
*/
+ @CallSuper
public void requestLayout() {
if (mMeasureCache != null) mMeasureCache.clear();
@@ -18871,7 +18891,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #dispatchNestedPreScroll(int, int, int[], int[])
*/
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
- int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+ int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) {
if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
int startX = 0;
@@ -18919,7 +18939,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return true if the parent consumed some or all of the scroll delta
* @see #dispatchNestedScroll(int, int, int, int, int[])
*/
- public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+ public boolean dispatchNestedPreScroll(int dx, int dy,
+ @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) {
if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
if (dx != 0 || dy != 0) {
int startX = 0;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e332135..744f665 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -1069,7 +1070,7 @@ public abstract class Window {
public abstract void setTitle(CharSequence title);
@Deprecated
- public abstract void setTitleColor(int textColor);
+ public abstract void setTitleColor(@ColorInt int textColor);
public abstract void openPanel(int featureId, KeyEvent event);
@@ -1835,6 +1836,7 @@ public abstract class Window {
/**
* @return the color of the status bar.
*/
+ @ColorInt
public abstract int getStatusBarColor();
/**
@@ -1852,11 +1854,12 @@ public abstract class Window {
* The transitionName for the view background will be "android:status:background".
* </p>
*/
- public abstract void setStatusBarColor(int color);
+ public abstract void setStatusBarColor(@ColorInt int color);
/**
* @return the color of the navigation bar.
*/
+ @ColorInt
public abstract int getNavigationBarColor();
/**
@@ -1874,7 +1877,7 @@ public abstract class Window {
* The transitionName for the view background will be "android:navigation:background".
* </p>
*/
- public abstract void setNavigationBarColor(int color);
+ public abstract void setNavigationBarColor(@ColorInt int color);
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 85d77cb..a5524d8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -16,6 +16,7 @@
package android.view.animation;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.RectF;
@@ -622,7 +623,7 @@ public abstract class Animation implements Cloneable {
* @param bg The background color. If 0, no background. Currently must
* be black, with any desired alpha level.
*/
- public void setBackgroundColor(int bg) {
+ public void setBackgroundColor(@ColorInt int bg) {
mBackgroundColor = bg;
}
@@ -753,6 +754,7 @@ public abstract class Animation implements Cloneable {
/**
* Returns the background color behind the animation.
*/
+ @ColorInt
public int getBackgroundColor() {
return mBackgroundColor;
}
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index 30c12ed..8eb5b5c 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -16,6 +16,7 @@
package android.view.animation;
+import android.annotation.FloatRange;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -163,7 +164,7 @@ public class Transformation {
* Sets the degree of transparency
* @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
*/
- public void setAlpha(float alpha) {
+ public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
mAlpha = alpha;
}
diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java
new file mode 100644
index 0000000..080d174
--- /dev/null
+++ b/core/java/android/webkit/WebResourceError.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * Encapsulates information about errors occured during loading of web resources. See
+ * {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)}
+ */
+public abstract class WebResourceError {
+ /**
+ * Gets the error code of the error. The code corresponds to one
+ * of the ERROR_* constants in {@link WebViewClient}.
+ *
+ * @return The error code of the error
+ */
+ public abstract int getErrorCode();
+
+ /**
+ * Gets the string describing the error. Descriptions are localized,
+ * and thus can be used for communicating the problem to the user.
+ *
+ * @return The description of the error
+ */
+ public abstract String getDescription();
+}
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index f487a4e..a42aaa7 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -25,7 +25,7 @@ import java.util.Map;
* class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
* response when the WebView requests a particular resource.
*/
-public class WebResourceResponse {
+public class WebResourceResponse extends WebResourceResponseBase {
private String mMimeType;
private String mEncoding;
private int mStatusCode;
@@ -75,38 +75,36 @@ public class WebResourceResponse {
}
/**
- * Sets the resource response's MIME type, for example text/html.
+ * Sets the resource response's MIME type, for example &quot;text/html&quot;.
*
- * @param mimeType the resource response's MIME type
+ * @param mimeType The resource response's MIME type
*/
public void setMimeType(String mimeType) {
mMimeType = mimeType;
}
/**
- * Gets the resource response's MIME type.
- *
- * @return the resource response's MIME type
+ * {@inheritDoc}
*/
+ @Override
public String getMimeType() {
return mMimeType;
}
/**
- * Sets the resource response's encoding, for example UTF-8. This is used
+ * Sets the resource response's encoding, for example &quot;UTF-8&quot;. This is used
* to decode the data from the input stream.
*
- * @param encoding the resource response's encoding
+ * @param encoding The resource response's encoding
*/
public void setEncoding(String encoding) {
mEncoding = encoding;
}
/**
- * Gets the resource response's encoding.
- *
- * @return the resource response's encoding
+ * {@inheritDoc}
*/
+ @Override
public String getEncoding() {
return mEncoding;
}
@@ -142,19 +140,17 @@ public class WebResourceResponse {
}
/**
- * Gets the resource response's status code.
- *
- * @return the resource response's status code.
+ * {@inheritDoc}
*/
+ @Override
public int getStatusCode() {
return mStatusCode;
}
/**
- * Gets the description of the resource response's status code.
- *
- * @return the description of the resource response's status code.
+ * {@inheritDoc}
*/
+ @Override
public String getReasonPhrase() {
return mReasonPhrase;
}
@@ -162,17 +158,16 @@ public class WebResourceResponse {
/**
* Sets the headers for the resource response.
*
- * @param headers mapping of header name -> header value.
+ * @param headers Mapping of header name -> header value.
*/
public void setResponseHeaders(Map<String, String> headers) {
mResponseHeaders = headers;
}
/**
- * Gets the headers for the resource response.
- *
- * @return the headers for the resource response.
+ * {@inheritDoc}
*/
+ @Override
public Map<String, String> getResponseHeaders() {
return mResponseHeaders;
}
@@ -190,15 +185,13 @@ public class WebResourceResponse {
throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " +
"not be passed to a WebResourceResponse");
}
-
mInputStream = data;
}
/**
- * Gets the input stream that provides the resource response's data.
- *
- * @return the input stream that provides the resource response's data
+ * {@inheritDoc}
*/
+ @Override
public InputStream getData() {
return mInputStream;
}
diff --git a/core/java/android/webkit/WebResourceResponseBase.java b/core/java/android/webkit/WebResourceResponseBase.java
new file mode 100644
index 0000000..cffde82
--- /dev/null
+++ b/core/java/android/webkit/WebResourceResponseBase.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Encapsulates a resource response received from the server.
+ * This is an abstract class used by WebView callbacks.
+ */
+public abstract class WebResourceResponseBase {
+ /**
+ * Gets the resource response's MIME type.
+ *
+ * @return The resource response's MIME type
+ */
+ public abstract String getMimeType();
+
+ /**
+ * Gets the resource response's encoding.
+ *
+ * @return The resource response's encoding
+ */
+ public abstract String getEncoding();
+
+ /**
+ * Gets the resource response's status code.
+ *
+ * @return The resource response's status code.
+ */
+ public abstract int getStatusCode();
+
+ /**
+ * Gets the description of the resource response's status code.
+ *
+ * @return The description of the resource response's status code.
+ */
+ public abstract String getReasonPhrase();
+
+ /**
+ * Gets the headers for the resource response.
+ *
+ * @return The headers for the resource response.
+ */
+ public abstract Map<String, String> getResponseHeaders();
+
+ /**
+ * Gets the input stream that provides the resource response's data.
+ *
+ * @return The input stream that provides the resource response's data
+ */
+ public abstract InputStream getData();
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 1d2c311..3df1293 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1285,7 +1285,7 @@ public abstract class WebSettings {
* strongly discouraged.
*
* @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW},
- * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+ * {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
*/
public abstract void setMixedContentMode(int mode);
@@ -1293,7 +1293,7 @@ public abstract class WebSettings {
* Gets the current behavior of the WebView with regard to loading insecure content from a
* secure origin.
* @return The current setting, one of {@link #MIXED_CONTENT_NEVER_ALLOW},
- * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+ * {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
*/
public abstract int getMixedContentMode();
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 01f9b37..34b8cf6 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -174,6 +174,8 @@ public class WebViewClient {
public static final int ERROR_FILE_NOT_FOUND = -14;
/** Too many requests during this load */
public static final int ERROR_TOO_MANY_REQUESTS = -15;
+ /** Request blocked by the browser */
+ public static final int ERROR_BLOCKED = -16;
/**
* Report an error to the host application. These errors are unrecoverable
@@ -183,12 +185,45 @@ public class WebViewClient {
* @param errorCode The error code corresponding to an ERROR_* value.
* @param description A String describing the error.
* @param failingUrl The url that failed to load.
+ * @deprecated Use {@link #onReceivedError(WebView, WebResourceRequest, WebResourceError)
+ * onReceivedError(WebView, WebResourceRequest, WebResourceError)} instead.
*/
+ @Deprecated
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
}
/**
+ * Report web resource loading error to the host application. These errors usually indicate
+ * inability to connect to the server. Note that unlike the deprecated version of the callback,
+ * the new version will be called for any resource (iframe, image, etc), not just for the main
+ * page. Thus, it is recommended to perform minimum required work in this callback.
+ * @param view The WebView that is initiating the callback.
+ * @param request The originating request.
+ * @param error Information about the error occured.
+ */
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ if (request.isForMainFrame()) {
+ onReceivedError(view,
+ error.getErrorCode(), error.getDescription(), request.getUrl().toString());
+ }
+ }
+
+ /**
+ * Notify the host application that an HTTP error has been received from the server while
+ * loading a resource. HTTP errors have status codes &gt;= 400. This callback will be called
+ * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to
+ * perform minimum required work in this callback. Note that the content of the server
+ * response may not be provided within the <b>errorResponse</b> parameter.
+ * @param view The WebView that is initiating the callback.
+ * @param request The originating request.
+ * @param errorResponse Information about the error occured.
+ */
+ public void onReceivedHttpError(
+ WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) {
+ }
+
+ /**
* As the host application if the browser should resend data as the
* requested page was a result of a POST. The default is to not resend the
* data.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a6e2952..168066a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.content.Context;
import android.content.Intent;
@@ -5982,7 +5983,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*
* @param color The background color
*/
- public void setCacheColorHint(int color) {
+ public void setCacheColorHint(@ColorInt int color) {
if (color != mCacheColorHint) {
mCacheColorHint = color;
int count = getChildCount();
@@ -6000,6 +6001,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @return The cache color hint
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @ColorInt
public int getCacheColorHint() {
return mCacheColorHint;
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 9b977fa..72cb0b5 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.Context;
import android.database.DataSetObserver;
import android.os.Parcelable;
@@ -276,7 +277,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
*
* @param listener The callback that will be invoked.
*/
- public void setOnItemClickListener(OnItemClickListener listener) {
+ public void setOnItemClickListener(@Nullable OnItemClickListener listener) {
mOnItemClickListener = listener;
}
@@ -284,6 +285,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
* @return The callback to be invoked with an item in this AdapterView has
* been clicked, or null id no callback has been set.
*/
+ @Nullable
public final OnItemClickListener getOnItemClickListener() {
return mOnItemClickListener;
}
@@ -394,10 +396,11 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
*
* @param listener The callback that will run
*/
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+ public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {
mOnItemSelectedListener = listener;
}
+ @Nullable
public final OnItemSelectedListener getOnItemSelectedListener() {
return mOnItemSelectedListener;
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index fd1c4b8..5bc16cb 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.Widget;
import android.content.Context;
@@ -140,7 +141,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
*/
- public void setSelectedWeekBackgroundColor(int color) {
+ public void setSelectedWeekBackgroundColor(@ColorInt int color) {
mDelegate.setSelectedWeekBackgroundColor(color);
}
@@ -151,6 +152,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
*/
+ @ColorInt
public int getSelectedWeekBackgroundColor() {
return mDelegate.getSelectedWeekBackgroundColor();
}
@@ -162,7 +164,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
*/
- public void setFocusedMonthDateColor(int color) {
+ public void setFocusedMonthDateColor(@ColorInt int color) {
mDelegate.setFocusedMonthDateColor(color);
}
@@ -173,6 +175,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
*/
+ @ColorInt
public int getFocusedMonthDateColor() {
return mDelegate.getFocusedMonthDateColor();
}
@@ -184,7 +187,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
*/
- public void setUnfocusedMonthDateColor(int color) {
+ public void setUnfocusedMonthDateColor(@ColorInt int color) {
mDelegate.setUnfocusedMonthDateColor(color);
}
@@ -195,6 +198,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
*/
+ @ColorInt
public int getUnfocusedMonthDateColor() {
return mDelegate.getUnfocusedMonthDateColor();
}
@@ -206,7 +210,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_weekNumberColor
*/
- public void setWeekNumberColor(int color) {
+ public void setWeekNumberColor(@ColorInt int color) {
mDelegate.setWeekNumberColor(color);
}
@@ -217,6 +221,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_weekNumberColor
*/
+ @ColorInt
public int getWeekNumberColor() {
return mDelegate.getWeekNumberColor();
}
@@ -228,7 +233,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
*/
- public void setWeekSeparatorLineColor(int color) {
+ public void setWeekSeparatorLineColor(@ColorInt int color) {
mDelegate.setWeekSeparatorLineColor(color);
}
@@ -239,6 +244,7 @@ public class CalendarView extends FrameLayout {
*
* @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
*/
+ @ColorInt
public int getWeekSeparatorLineColor() {
return mDelegate.getWeekSeparatorLineColor();
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 391347e..9019f31 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.graphics.PorterDuff;
@@ -292,7 +293,7 @@ public class EdgeEffect {
*
* @param color Color in argb
*/
- public void setColor(int color) {
+ public void setColor(@ColorInt int color) {
mPaint.setColor(color);
}
@@ -300,6 +301,7 @@ public class EdgeEffect {
* Return the color of this edge effect in argb.
* @return The color of this edge effect in argb
*/
+ @ColorInt
public int getColor() {
return mPaint.getColor();
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f8e207f..8197b3d 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -128,7 +128,7 @@ public class Editor {
// Each Editor manages its own undo stack.
private final UndoManager mUndoManager = new UndoManager();
private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
- final InputFilter mUndoInputFilter = new UndoInputFilter(this);
+ final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this);
boolean mAllowUndo = true;
// Cursor Controllers.
@@ -217,6 +217,12 @@ public class Editor {
WordIterator mWordIterator;
SpellChecker mSpellChecker;
+ // This word iterator is set with text and used to determine word boundaries
+ // when a user is selecting text.
+ private WordIterator mWordIteratorWithText;
+ // Indicate that the text in the word iterator needs to be updated.
+ private boolean mUpdateWordIteratorText;
+
private Rect mTempRect;
private TextView mTextView;
@@ -240,6 +246,15 @@ public class Editor {
mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
}
+ /**
+ * Forgets all undo and redo operations for this Editor.
+ */
+ void forgetUndoRedo() {
+ UndoOwner[] owners = { mUndoOwner };
+ mUndoManager.forgetUndos(owners, -1 /* all */);
+ mUndoManager.forgetRedos(owners, -1 /* all */);
+ }
+
boolean canUndo() {
UndoOwner[] owners = { mUndoOwner };
return mAllowUndo && mUndoManager.countUndos(owners) > 0;
@@ -689,9 +704,52 @@ public class Editor {
return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod;
}
+ private int getWordStart(int offset) {
+ // FIXME - For this and similar methods we're not doing anything to check if there's
+ // a LocaleSpan in the text, this may be something we should try handling or checking for.
+ int retOffset = getWordIteratorWithText().getBeginning(offset);
+ if (retOffset == BreakIterator.DONE) retOffset = offset;
+ return retOffset;
+ }
+
+ private int getWordEnd(int offset, boolean includePunctuation) {
+ int retOffset = getWordIteratorWithText().getEnd(offset);
+ if (retOffset == BreakIterator.DONE) {
+ retOffset = offset;
+ } else if (includePunctuation) {
+ retOffset = handlePunctuation(retOffset);
+ }
+ return retOffset;
+ }
+
+ private boolean isEndBoundary(int offset) {
+ int thisEnd = getWordEnd(offset, false);
+ return offset == thisEnd;
+ }
+
+ private boolean isStartBoundary(int offset) {
+ int thisStart = getWordStart(offset);
+ return thisStart == offset;
+ }
+
+ private int handlePunctuation(int offset) {
+ // FIXME - Check with UX how repeated ending punctuation should be handled.
+ // FIXME - Check with UX if / how we would handle non sentence ending characters.
+ // FIXME - Consider punctuation in different languages.
+ CharSequence text = mTextView.getText();
+ if (offset < text.length()) {
+ int c = Character.codePointAt(text, offset);
+ if (c == 0x002e /* period */|| c == 0x003f /* question mark */
+ || c == 0x0021 /* exclamation mark */) {
+ offset = Character.offsetByCodePoints(text, offset, 1);
+ }
+ }
+ return offset;
+ }
+
/**
- * Adjusts selection to the word under last touch offset.
- * Return true if the operation was successfully performed.
+ * Adjusts selection to the word under last touch offset. Return true if the operation was
+ * successfully performed.
*/
private boolean selectCurrentWord() {
if (!canSelectText()) {
@@ -738,6 +796,8 @@ public class Editor {
selectionStart = ((Spanned) mTextView.getText()).getSpanStart(urlSpan);
selectionEnd = ((Spanned) mTextView.getText()).getSpanEnd(urlSpan);
} else {
+ // FIXME - We should check if there's a LocaleSpan in the text, this may be
+ // something we should try handling or checking for.
final WordIterator wordIterator = getWordIterator();
wordIterator.setCharSequence(mTextView.getText(), minOffset, maxOffset);
@@ -760,6 +820,7 @@ public class Editor {
void onLocaleChanged() {
// Will be re-created on demand in getWordIterator with the proper new locale
mWordIterator = null;
+ mWordIteratorWithText = null;
}
/**
@@ -772,6 +833,23 @@ public class Editor {
return mWordIterator;
}
+ private WordIterator getWordIteratorWithText() {
+ if (mWordIteratorWithText == null) {
+ mWordIteratorWithText = new WordIterator(mTextView.getTextServicesLocale());
+ mUpdateWordIteratorText = true;
+ }
+ if (mUpdateWordIteratorText) {
+ // FIXME - Shouldn't copy all of the text as only the area of the text relevant
+ // to the user's selection is needed. A possible solution would be to
+ // copy some number N of characters near the selection and then when the
+ // user approaches N then we'd do another copy of the next N characters.
+ CharSequence text = mTextView.getText();
+ mWordIteratorWithText.setCharSequence(text, 0, text.length());
+ mUpdateWordIteratorText = false;
+ }
+ return mWordIteratorWithText;
+ }
+
private long getCharRange(int offset) {
final int textLength = mTextView.getText().length();
if (offset + 1 < textLength) {
@@ -920,9 +998,8 @@ public class Editor {
mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
stopSelectionActionMode();
} else {
- getSelectionController().hide();
- selectCurrentWord();
- getSelectionController().show();
+ stopSelectionActionMode();
+ startSelectionActionMode();
}
handled = true;
}
@@ -1058,6 +1135,9 @@ public class Editor {
void sendOnTextChanged(int start, int after) {
updateSpellCheckSpans(start, start + after, false);
+ // Flip flag to indicate the word iterator needs to have the text reset.
+ mUpdateWordIteratorText = true;
+
// Hide the controllers as soon as text is modified (typing, procedural...)
// We do not hide the span controllers, since they can be added when a new text is
// inserted into the text view (voice IME).
@@ -1143,6 +1223,7 @@ public class Editor {
ims.mChangedEnd = EXTRACT_UNKNOWN;
ims.mContentChanged = false;
}
+ mUndoInputFilter.beginBatchEdit();
mTextView.onBeginBatchEdit();
}
}
@@ -1169,6 +1250,7 @@ public class Editor {
void finishBatchEdit(final InputMethodState ims) {
mTextView.onEndBatchEdit();
+ mUndoInputFilter.endBatchEdit();
if (ims.mContentChanged || ims.mSelectionModeChanged) {
mTextView.updateAfterEdit();
@@ -1613,6 +1695,9 @@ public class Editor {
}
}
+ if (selectionStarted) {
+ getSelectionController().enterDrag();
+ }
return selectionStarted;
}
@@ -2894,7 +2979,6 @@ public class Editor {
}
if (menu.hasVisibleItems() || mode.getCustomView() != null) {
- getSelectionController().show();
mTextView.setHasTransientState(true);
return true;
} else {
@@ -3232,6 +3316,8 @@ public class Editor {
private Runnable mActionPopupShower;
// Minimum touch target size for handles
private int mMinSize;
+ // Indicates the line of text that the handle is on.
+ protected int mLine = -1;
public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(mTextView.getContext());
@@ -3407,6 +3493,7 @@ public class Editor {
addPositionToTouchUpFilter(offset);
}
final int line = layout.getLineForOffset(offset);
+ mLine = line;
mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX -
getHorizontalOffset() + getCursorOffset());
@@ -3456,6 +3543,30 @@ public class Editor {
}
}
+ public void showAtLocation(int offset) {
+ // TODO - investigate if there's a better way to show the handles
+ // after the drag accelerator has occured.
+ int[] tmpCords = new int[2];
+ mTextView.getLocationInWindow(tmpCords);
+
+ Layout layout = mTextView.getLayout();
+ int posX = tmpCords[0];
+ int posY = tmpCords[1];
+
+ final int line = layout.getLineForOffset(offset);
+
+ int startX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f
+ - mHotspotX - getHorizontalOffset() + getCursorOffset());
+ int startY = layout.getLineBottom(line);
+
+ // Take TextView's padding and scroll into account.
+ startX += mTextView.viewportToContentHorizontalOffset();
+ startY += mTextView.viewportToContentVerticalOffset();
+
+ mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
+ startX + posX, startY + posY);
+ }
+
@Override
protected void onDraw(Canvas c) {
final int drawWidth = mDrawable.getIntrinsicWidth();
@@ -3694,6 +3805,12 @@ public class Editor {
}
private class SelectionStartHandleView extends HandleView {
+ // The previous offset this handle was at.
+ private int mPrevOffset;
+ // Indicates whether the cursor is making adjustments within a word.
+ private boolean mInWord = false;
+ // Offset to track difference between touch and word boundary.
+ protected int mTouchWordOffset;
public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
@@ -3701,11 +3818,7 @@ public class Editor {
@Override
protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
- if (isRtlRun) {
- return drawable.getIntrinsicWidth() / 4;
- } else {
- return (drawable.getIntrinsicWidth() * 3) / 4;
- }
+ return isRtlRun ? 0 : drawable.getIntrinsicWidth();
}
@Override
@@ -3727,21 +3840,81 @@ public class Editor {
@Override
public void updatePosition(float x, float y) {
- int offset = mTextView.getOffsetForPosition(x, y);
-
- // Handles can not cross and selection is at least one character
- final int selectionEnd = mTextView.getSelectionEnd();
- if (offset >= selectionEnd) offset = Math.max(0, selectionEnd - 1);
+ final int trueOffset = mTextView.getOffsetForPosition(x, y);
+ final int currLine = mTextView.getLineAtCoordinate(y);
+ int offset = trueOffset;
+ boolean positionCursor = false;
+
+ int end = getWordEnd(offset, true);
+ int start = getWordStart(offset);
+
+ if (offset < mPrevOffset) {
+ // User is increasing the selection.
+ if (!mInWord || currLine < mLine) {
+ // We're not in a word, or we're on a different line so we'll expand by
+ // word. First ensure the user has at least entered the next word.
+ int offsetToWord = Math.min((end - start) / 2, 2);
+ if (offset <= end - offsetToWord || currLine < mLine) {
+ offset = start;
+ } else {
+ offset = mPrevOffset;
+ }
+ }
+ mPrevOffset = offset;
+ mTouchWordOffset = trueOffset - offset;
+ mInWord = !isStartBoundary(offset);
+ positionCursor = true;
+ } else if (offset - mTouchWordOffset > mPrevOffset) {
+ // User is shrinking the selection.
+ if (currLine > mLine) {
+ // We're on a different line, so we'll snap to word boundaries.
+ offset = end;
+ }
+ offset -= mTouchWordOffset;
+ mPrevOffset = offset;
+ mInWord = !isEndBoundary(offset);
+ positionCursor = true;
+ }
- positionAtCursorOffset(offset, false);
+ // Handles can not cross and selection is at least one character.
+ if (positionCursor) {
+ final int selectionEnd = mTextView.getSelectionEnd();
+ if (offset >= selectionEnd) {
+ // We can't cross the handles so let's just constrain the Y value.
+ int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+ if (alteredOffset >= selectionEnd) {
+ // Can't pass the other drag handle.
+ offset = Math.max(0, selectionEnd - 1);
+ } else {
+ offset = alteredOffset;
+ }
+ }
+ positionAtCursorOffset(offset, false);
+ }
}
public ActionPopupWindow getActionPopupWindow() {
return mActionPopupWindow;
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean superResult = super.onTouchEvent(event);
+ if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ // Reset the touch word offset when the user has lifted their finger.
+ mTouchWordOffset = 0;
+ }
+ return superResult;
+ }
}
private class SelectionEndHandleView extends HandleView {
+ // The previous offset this handle was at.
+ private int mPrevOffset;
+ // Indicates whether the cursor is making adjustments within a word.
+ private boolean mInWord = false;
+ // Offset to track difference between touch and word boundary.
+ protected int mTouchWordOffset;
public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
@@ -3749,11 +3922,7 @@ public class Editor {
@Override
protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
- if (isRtlRun) {
- return (drawable.getIntrinsicWidth() * 3) / 4;
- } else {
- return drawable.getIntrinsicWidth() / 4;
- }
+ return isRtlRun ? drawable.getIntrinsicWidth() : 0;
}
@Override
@@ -3775,20 +3944,72 @@ public class Editor {
@Override
public void updatePosition(float x, float y) {
- int offset = mTextView.getOffsetForPosition(x, y);
-
- // Handles can not cross and selection is at least one character
- final int selectionStart = mTextView.getSelectionStart();
- if (offset <= selectionStart) {
- offset = Math.min(selectionStart + 1, mTextView.getText().length());
+ final int trueOffset = mTextView.getOffsetForPosition(x, y);
+ final int currLine = mTextView.getLineAtCoordinate(y);
+ int offset = trueOffset;
+ boolean positionCursor = false;
+
+ int end = getWordEnd(offset, true);
+ int start = getWordStart(offset);
+
+ if (offset > mPrevOffset) {
+ // User is increasing the selection.
+ if (!mInWord || currLine > mLine) {
+ // We're not in a word, or we're on a different line so we'll expand by
+ // word. First ensure the user has at least entered the next word.
+ int midPoint = Math.min((end - start) / 2, 2);
+ if (offset >= start + midPoint || currLine > mLine) {
+ offset = end;
+ } else {
+ offset = mPrevOffset;
+ }
+ }
+ mPrevOffset = offset;
+ mTouchWordOffset = offset - trueOffset;
+ mInWord = !isEndBoundary(offset);
+ positionCursor = true;
+ } else if (offset + mTouchWordOffset < mPrevOffset) {
+ // User is shrinking the selection.
+ if (currLine > mLine) {
+ // We're on a different line, so we'll snap to word boundaries.
+ offset = getWordStart(offset);
+ }
+ offset += mTouchWordOffset;
+ mPrevOffset = offset;
+ positionCursor = true;
+ mInWord = !isStartBoundary(offset);
}
- positionAtCursorOffset(offset, false);
+ if (positionCursor) {
+ final int selectionStart = mTextView.getSelectionStart();
+ if (offset <= selectionStart) {
+ // We can't cross the handles so let's just constrain the Y value.
+ int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+ int length = mTextView.getText().length();
+ if (alteredOffset <= selectionStart) {
+ // Can't pass the other drag handle.
+ offset = Math.min(selectionStart + 1, length);
+ } else {
+ offset = Math.min(alteredOffset, length);
+ }
+ }
+ positionAtCursorOffset(offset, false);
+ }
}
public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
mActionPopupWindow = actionPopupWindow;
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean superResult = super.onTouchEvent(event);
+ if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ // Reset the touch word offset when the user has lifted their finger.
+ mTouchWordOffset = 0;
+ }
+ return superResult;
+ }
}
/**
@@ -3871,6 +4092,11 @@ public class Editor {
private float mDownPositionX, mDownPositionY;
private boolean mGestureStayedInTapRegion;
+ // Where the user first starts the drag motion.
+ private int mStartOffset = -1;
+ // Indicates whether the user is selecting text and using the drag accelerator.
+ private boolean mDragAcceleratorActive;
+
SelectionModifierCursorController() {
resetTouchOffsets();
}
@@ -3920,6 +4146,22 @@ public class Editor {
if (mEndHandle != null) mEndHandle.hide();
}
+ public void enterDrag() {
+ // Just need to init the handles / hide insertion cursor.
+ show();
+ mDragAcceleratorActive = true;
+ // Start location of selection.
+ mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX,
+ mLastDownPositionY);
+ // Don't show the handles until user has lifted finger.
+ hide();
+
+ // This stops scrolling parents from intercepting the touch event, allowing
+ // the user to continue dragging across the screen to select text; TextView will
+ // scroll as necessary.
+ mTextView.getParent().requestDisallowInterceptTouchEvent(true);
+ }
+
public void onTouchEvent(MotionEvent event) {
// This is done even when the View does not have focus, so that long presses can start
// selection and tap can move cursor from this tap position.
@@ -3928,7 +4170,7 @@ public class Editor {
final float x = event.getX();
final float y = event.getY();
- // Remember finger down position, to be able to start selection from there
+ // Remember finger down position, to be able to start selection from there.
mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(x, y);
// Double tap detection
@@ -3967,23 +4209,112 @@ public class Editor {
break;
case MotionEvent.ACTION_MOVE:
+ final ViewConfiguration viewConfiguration = ViewConfiguration.get(
+ mTextView.getContext());
+
if (mGestureStayedInTapRegion) {
final float deltaX = event.getX() - mDownPositionX;
final float deltaY = event.getY() - mDownPositionY;
final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
- final ViewConfiguration viewConfiguration = ViewConfiguration.get(
- mTextView.getContext());
int doubleTapTouchSlop = viewConfiguration.getScaledDoubleTapTouchSlop();
if (distanceSquared > doubleTapTouchSlop * doubleTapTouchSlop) {
mGestureStayedInTapRegion = false;
}
}
+
+ if (mStartHandle != null && mStartHandle.isShowing()) {
+ // Don't do the drag if the handles are showing already.
+ break;
+ }
+
+ if (mStartOffset != -1) {
+ final int rawOffset = mTextView.getOffsetForPosition(event.getX(),
+ event.getY());
+ int offset = rawOffset;
+
+ // We don't start "dragging" until the user is past the initial word that
+ // gets selected on long press.
+ int firstWordStart = getWordStart(mStartOffset);
+ int firstWordEnd = getWordEnd(mStartOffset, false);
+ if (offset > firstWordEnd || offset < firstWordStart) {
+
+ // Basically the goal in the below code is to have the highlight be
+ // offset so that your finger isn't covering the end point.
+ int fingerOffset = viewConfiguration.getScaledTouchSlop();
+ float mx = event.getX();
+ float my = event.getY();
+ if (mx > fingerOffset) mx -= fingerOffset;
+ if (my > fingerOffset) my -= fingerOffset;
+ offset = mTextView.getOffsetForPosition(mx, my);
+
+ // Perform the check for closeness at edge of view, if we're very close
+ // don't adjust the offset to be in front of the finger - otherwise the
+ // user can't select words at the edge.
+ if (mTextView.getWidth() - fingerOffset > mx) {
+ // We're going by word, so we need to make sure that the offset
+ // that we get is within this, so we'll get the previous boundary.
+ final WordIterator wordIterator = getWordIteratorWithText();
+
+ final int precedingOffset = wordIterator.preceding(offset);
+ if (mStartOffset < offset) {
+ // Expanding with bottom handle, in this case the selection end
+ // is before the finger.
+ offset = Math.max(precedingOffset - 1, 0);
+ } else {
+ // Expand with the start handle, in this case the selection
+ // start is before the finger.
+ if (precedingOffset == WordIterator.DONE) {
+ offset = 0;
+ } else {
+ offset = wordIterator.preceding(precedingOffset);
+ }
+ }
+ }
+ if (offset == WordIterator.DONE)
+ offset = rawOffset;
+
+ // Need to adjust start offset based on direction of movement.
+ int newStart = mStartOffset < offset ? getWordStart(mStartOffset)
+ : getWordEnd(mStartOffset, true);
+ Selection.setSelection((Spannable) mTextView.getText(), newStart,
+ offset);
+ }
+ }
break;
case MotionEvent.ACTION_UP:
mPreviousTapUpTime = SystemClock.uptimeMillis();
+ if (mDragAcceleratorActive) {
+ // No longer dragging to select text, let the parent intercept events.
+ mTextView.getParent().requestDisallowInterceptTouchEvent(false);
+
+ show();
+ int startOffset = mTextView.getSelectionStart();
+ int endOffset = mTextView.getSelectionEnd();
+
+ // Since we don't let drag handles pass once they're visible, we need to
+ // make sure the start / end locations are correct because the user *can*
+ // switch directions during the initial drag.
+ if (endOffset < startOffset) {
+ int tmp = endOffset;
+ endOffset = startOffset;
+ startOffset = tmp;
+
+ // Also update the selection with the right offsets in this case.
+ Selection.setSelection((Spannable) mTextView.getText(),
+ startOffset, endOffset);
+ }
+
+ // Need to do this to display the handles.
+ mStartHandle.showAtLocation(startOffset);
+ mEndHandle.showAtLocation(endOffset);
+
+ // No longer the first dragging motion, reset.
+ mDragAcceleratorActive = false;
+ mStartOffset = -1;
+ }
break;
}
}
@@ -4010,6 +4341,8 @@ public class Editor {
public void resetTouchOffsets() {
mMinTouchOffset = mMaxTouchOffset = -1;
+ mStartOffset = -1;
+ mDragAcceleratorActive = false;
}
/**
@@ -4019,6 +4352,13 @@ public class Editor {
return mStartHandle != null && mStartHandle.isDragging();
}
+ /**
+ * @return true if the user is selecting text using the drag accelerator.
+ */
+ public boolean isDragAcceleratorActive() {
+ return mDragAcceleratorActive;
+ }
+
public void onTouchModeChanged(boolean isInTouchMode) {
if (!isInTouchMode) {
hide();
@@ -4217,10 +4557,30 @@ public class Editor {
public static class UndoInputFilter implements InputFilter {
private final Editor mEditor;
+ // Whether the current filter pass is directly caused by an end-user text edit.
+ private boolean mIsUserEdit;
+
+ // Whether this is the first pass through the filter for a given end-user text edit.
+ private boolean mFirstFilterPass;
+
public UndoInputFilter(Editor editor) {
mEditor = editor;
}
+ /**
+ * Signals that a user-triggered edit is starting.
+ */
+ public void beginBatchEdit() {
+ if (DEBUG_UNDO) Log.d(TAG, "beginBatchEdit");
+ mIsUserEdit = true;
+ mFirstFilterPass = true;
+ }
+
+ public void endBatchEdit() {
+ if (DEBUG_UNDO) Log.d(TAG, "endBatchEdit");
+ mIsUserEdit = false;
+ }
+
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
@@ -4229,36 +4589,24 @@ public class Editor {
"dest=" + dest + " (" + dstart + "-" + dend + ")");
}
- if (!mEditor.mAllowUndo) {
- if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
- return null;
- }
-
- final UndoManager um = mEditor.mUndoManager;
- if (um.isInUndo()) {
- if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
+ // Check to see if this edit should be tracked for undo.
+ if (!canUndoEdit(source, start, end, dest, dstart, dend)) {
return null;
}
- // Text filters run before input operations are applied. However, some input operations
- // are invalid and will throw exceptions when applied. This is common in tests. Don't
- // attempt to undo invalid operations.
- if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
- if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
- return null;
- }
-
- // Earlier filters can rewrite input to be a no-op, for example due to a length limit
- // on an input field. Skip no-op changes.
- if (start == end && dstart == dend) {
- if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
- return null;
- }
+ // An application may install a TextWatcher to provide additional modifications after
+ // the initial input filters run (e.g. a credit card formatter that adds spaces to a
+ // string). This results in multiple filter() calls for what the user considers to be
+ // a single operation. Always undo the whole set of changes in one step.
+ final boolean forceMerge = !mFirstFilterPass;
+ mFirstFilterPass = false;
// Build a new operation with all the information from this edit.
- EditOperation edit = new EditOperation(mEditor, source, start, end, dest, dstart, dend);
+ EditOperation edit = new EditOperation(mEditor, forceMerge,
+ source, start, end, dest, dstart, dend);
// Fetch the last edit operation and attempt to merge in the new edit.
+ final UndoManager um = mEditor.mUndoManager;
um.beginUpdate("Edit text");
EditOperation lastEdit = um.getLastOperation(
EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
@@ -4266,6 +4614,12 @@ public class Editor {
// Add this as the first edit.
if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+ } else if (!mIsUserEdit) {
+ // An application directly modified the Editable outside of a text edit. Treat this
+ // as a new change and don't attempt to merge.
+ if (DEBUG_UNDO) Log.d(TAG, "non-user edit, new op " + edit);
+ um.commitState(mEditor.mUndoOwner);
+ um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
} else if (lastEdit.mergeWith(edit)) {
// Merge succeeded, nothing else to do.
if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit);
@@ -4278,6 +4632,36 @@ public class Editor {
um.endUpdate();
return null; // Text not changed.
}
+
+ private boolean canUndoEdit(CharSequence source, int start, int end,
+ Spanned dest, int dstart, int dend) {
+ if (!mEditor.mAllowUndo) {
+ if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
+ return false;
+ }
+
+ if (mEditor.mUndoManager.isInUndo()) {
+ if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
+ return false;
+ }
+
+ // Text filters run before input operations are applied. However, some input operations
+ // are invalid and will throw exceptions when applied. This is common in tests. Don't
+ // attempt to undo invalid operations.
+ if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
+ if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
+ return false;
+ }
+
+ // Earlier filters can rewrite input to be a no-op, for example due to a length limit
+ // on an input field. Skip no-op changes.
+ if (start == end && dstart == dend) {
+ if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
+ return false;
+ }
+
+ return true;
+ }
}
/**
@@ -4289,6 +4673,7 @@ public class Editor {
private static final int TYPE_REPLACE = 2;
private int mType;
+ private boolean mForceMerge;
private String mOldText;
private int mOldTextStart;
private String mNewText;
@@ -4300,10 +4685,12 @@ public class Editor {
/**
* Constructs an edit operation from a text input operation that replaces the range
* (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}.
+ * If forceMerge is true then always forcibly merge this operation with any previous one.
*/
- public EditOperation(Editor editor, CharSequence source, int start, int end,
- Spanned dest, int dstart, int dend) {
+ public EditOperation(Editor editor, boolean forceMerge,
+ CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
super(editor.mUndoOwner);
+ mForceMerge = forceMerge;
mOldText = dest.subSequence(dstart, dend).toString();
mNewText = source.subSequence(start, end).toString();
@@ -4331,6 +4718,7 @@ public class Editor {
public EditOperation(Parcel src, ClassLoader loader) {
super(src, loader);
mType = src.readInt();
+ mForceMerge = src.readInt() != 0;
mOldText = src.readString();
mOldTextStart = src.readInt();
mNewText = src.readString();
@@ -4342,6 +4730,7 @@ public class Editor {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
+ dest.writeInt(mForceMerge ? 1 : 0);
dest.writeString(mOldText);
dest.writeInt(mOldTextStart);
dest.writeString(mNewText);
@@ -4350,6 +4739,14 @@ public class Editor {
dest.writeInt(mNewCursorPos);
}
+ private int getNewTextEnd() {
+ return mNewTextStart + mNewText.length();
+ }
+
+ private int getOldTextEnd() {
+ return mOldTextStart + mOldText.length();
+ }
+
@Override
public void commit() {
}
@@ -4358,14 +4755,20 @@ public class Editor {
public void undo() {
if (DEBUG_UNDO) Log.d(TAG, "undo");
// Remove the new text and insert the old.
- modifyText(mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, mOldCursorPos);
+ Editor editor = getOwnerData();
+ Editable text = (Editable) editor.mTextView.getText();
+ modifyText(text, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+ mOldCursorPos);
}
@Override
public void redo() {
if (DEBUG_UNDO) Log.d(TAG, "redo");
// Remove the old text and insert the new.
- modifyText(mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, mNewCursorPos);
+ Editor editor = getOwnerData();
+ Editable text = (Editable) editor.mTextView.getText();
+ modifyText(text, mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart,
+ mNewCursorPos);
}
/**
@@ -4375,6 +4778,14 @@ public class Editor {
* object unchanged.
*/
private boolean mergeWith(EditOperation edit) {
+ if (DEBUG_UNDO) {
+ Log.d(TAG, "mergeWith old " + this);
+ Log.d(TAG, "mergeWith new " + edit);
+ }
+ if (edit.mForceMerge) {
+ forceMergeWith(edit);
+ return true;
+ }
switch (mType) {
case TYPE_INSERT:
return mergeInsertWith(edit);
@@ -4388,7 +4799,6 @@ public class Editor {
}
private boolean mergeInsertWith(EditOperation edit) {
- if (DEBUG_UNDO) Log.d(TAG, "mergeInsertWith " + edit);
// Only merge continuous insertions.
if (edit.mType != TYPE_INSERT) {
return false;
@@ -4404,7 +4814,6 @@ public class Editor {
// TODO: Support forward delete.
private boolean mergeDeleteWith(EditOperation edit) {
- if (DEBUG_UNDO) Log.d(TAG, "mergeDeleteWith " + edit);
// Only merge continuous deletes.
if (edit.mType != TYPE_DELETE) {
return false;
@@ -4420,11 +4829,8 @@ public class Editor {
}
private boolean mergeReplaceWith(EditOperation edit) {
- if (DEBUG_UNDO) Log.d(TAG, "mergeReplaceWith " + edit);
- // Replacements can merge only with adjacent inserts and adjacent replacements.
- if (edit.mType == TYPE_DELETE ||
- getNewTextEnd() != edit.mOldTextStart ||
- edit.mOldTextStart != edit.mNewTextStart) {
+ // Replacements can merge only with adjacent inserts.
+ if (edit.mType != TYPE_INSERT || getNewTextEnd() != edit.mNewTextStart) {
return false;
}
mOldText += edit.mOldText;
@@ -4433,18 +4839,42 @@ public class Editor {
return true;
}
- private int getNewTextEnd() {
- return mNewTextStart + mNewText.length();
- }
+ /**
+ * Forcibly creates a single merged edit operation by simulating the entire text
+ * contents being replaced.
+ */
+ private void forceMergeWith(EditOperation edit) {
+ if (DEBUG_UNDO) Log.d(TAG, "forceMerge");
+ Editor editor = getOwnerData();
- private int getOldTextEnd() {
- return mOldTextStart + mOldText.length();
+ // Copy the text of the current field.
+ // NOTE: Using StringBuilder instead of SpannableStringBuilder would be somewhat faster,
+ // but would require two parallel implementations of modifyText() because Editable and
+ // StringBuilder do not share an interface for replace/delete/insert.
+ Editable editable = (Editable) editor.mTextView.getText();
+ Editable originalText = new SpannableStringBuilder(editable.toString());
+
+ // Roll back the last operation.
+ modifyText(originalText, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+ mOldCursorPos);
+
+ // Clone the text again and apply the new operation.
+ Editable finalText = new SpannableStringBuilder(editable.toString());
+ modifyText(finalText, edit.mOldTextStart, edit.getOldTextEnd(), edit.mNewText,
+ edit.mNewTextStart, edit.mNewCursorPos);
+
+ // Convert this operation into a non-mergeable replacement of the entire string.
+ mType = TYPE_REPLACE;
+ mNewText = finalText.toString();
+ mNewTextStart = 0;
+ mOldText = originalText.toString();
+ mOldTextStart = 0;
+ mNewCursorPos = edit.mNewCursorPos;
+ // mOldCursorPos is unchanged.
}
- private void modifyText(int deleteFrom, int deleteTo, CharSequence newText,
- int newTextInsertAt, int newCursorPos) {
- Editor editor = getOwnerData();
- Editable text = (Editable) editor.mTextView.getText();
+ private static void modifyText(Editable text, int deleteFrom, int deleteTo,
+ CharSequence newText, int newTextInsertAt, int newCursorPos) {
// Apply the edit if it is still valid.
if (isValidRange(text, deleteFrom, deleteTo) &&
newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) {
@@ -4462,10 +4892,22 @@ public class Editor {
}
}
+ private String getTypeString() {
+ switch (mType) {
+ case TYPE_INSERT:
+ return "insert";
+ case TYPE_DELETE:
+ return "delete";
+ case TYPE_REPLACE:
+ return "replace";
+ default:
+ return "";
+ }
+ }
+
@Override
public String toString() {
- return "EditOperation: [" +
- "mType=" + mType + ", " +
+ return "[mType=" + getTypeString() + ", " +
"mOldText=" + mOldText + ", " +
"mOldTextStart=" + mOldTextStart + ", " +
"mNewText=" + mNewText + ", " +
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index e8dc11f..f6d198b 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -101,15 +101,16 @@ public class FrameLayout extends ViewGroup {
super(context);
}
- public FrameLayout(Context context, AttributeSet attrs) {
+ public FrameLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public FrameLayout(
+ Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index e8fe191..6cc4bda 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -141,7 +141,9 @@ import static java.lang.Math.min;
* view was alone in a column, that column would itself collapse to zero width if and only if
* no gravity was defined on the view. If gravity was defined, then the gone-marked
* view has no effect on the layout and the container should be laid out as if the view
- * had never been added to it.
+ * had never been added to it. GONE views are taken to have zero weight during excess space
+ * distribution.
+ * <p>
* These statements apply equally to rows as well as columns, and to groups of rows or columns.
*
* <p>
@@ -1010,12 +1012,10 @@ public class GridLayout extends ViewGroup {
LayoutParams lp = getLayoutParams(c);
if (firstPass) {
measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
- mHorizontalAxis.recordOriginalMeasurement(i);
- mVerticalAxis.recordOriginalMeasurement(i);
} else {
boolean horizontal = (mOrientation == HORIZONTAL);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- if (spec.alignment == FILL) {
+ if (spec.getAbsoluteAlignment(horizontal) == FILL) {
Interval span = spec.span;
Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
int[] locations = axis.getLocations();
@@ -1091,11 +1091,6 @@ public class GridLayout extends ViewGroup {
invalidateValues();
}
- final Alignment getAlignment(Alignment alignment, boolean horizontal) {
- return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
- (horizontal ? START : BASELINE);
- }
-
// Layout container
/**
@@ -1150,8 +1145,8 @@ public class GridLayout extends ViewGroup {
int pWidth = getMeasurement(c, true);
int pHeight = getMeasurement(c, false);
- Alignment hAlign = getAlignment(columnSpec.alignment, true);
- Alignment vAlign = getAlignment(rowSpec.alignment, false);
+ Alignment hAlign = columnSpec.getAbsoluteAlignment(true);
+ Alignment vAlign = rowSpec.getAbsoluteAlignment(false);
Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
@@ -1234,7 +1229,6 @@ public class GridLayout extends ViewGroup {
public boolean hasWeights;
public boolean hasWeightsValid = false;
- public int[] originalMeasurements;
public int[] deltas;
boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
@@ -1297,7 +1291,7 @@ public class GridLayout extends ViewGroup {
// we must include views that are GONE here, see introductory javadoc
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
+ Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds();
assoc.put(spec, bounds);
}
return assoc.pack();
@@ -1313,9 +1307,8 @@ public class GridLayout extends ViewGroup {
// we must include views that are GONE here, see introductory javadoc
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- int size = (spec.weight == 0) ?
- getMeasurementIncludingMargin(c, horizontal) :
- getOriginalMeasurements()[i] + getDeltas()[i];
+ int size = getMeasurementIncludingMargin(c, horizontal) +
+ ((spec.weight == 0) ? 0 : getDeltas()[i]);
groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
}
}
@@ -1703,7 +1696,11 @@ public class GridLayout extends ViewGroup {
private boolean computeHasWeights() {
for (int i = 0, N = getChildCount(); i < N; i++) {
- LayoutParams lp = getLayoutParams(getChildAt(i));
+ final View child = getChildAt(i);
+ if (child.getVisibility() == View.GONE) {
+ continue;
+ }
+ LayoutParams lp = getLayoutParams(child);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
if (spec.weight != 0) {
return true;
@@ -1720,19 +1717,6 @@ public class GridLayout extends ViewGroup {
return hasWeights;
}
- public int[] getOriginalMeasurements() {
- if (originalMeasurements == null) {
- originalMeasurements = new int[getChildCount()];
- }
- return originalMeasurements;
- }
-
- private void recordOriginalMeasurement(int i) {
- if (hasWeights()) {
- getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal);
- }
- }
-
public int[] getDeltas() {
if (deltas == null) {
deltas = new int[getChildCount()];
@@ -1743,7 +1727,10 @@ public class GridLayout extends ViewGroup {
private void shareOutDelta(int totalDelta, float totalWeight) {
Arrays.fill(deltas, 0);
for (int i = 0, N = getChildCount(); i < N; i++) {
- View c = getChildAt(i);
+ final View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) {
+ continue;
+ }
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
float weight = spec.weight;
@@ -1796,6 +1783,9 @@ public class GridLayout extends ViewGroup {
float totalWeight = 0f;
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) {
+ continue;
+ }
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
totalWeight += spec.weight;
@@ -1891,7 +1881,6 @@ public class GridLayout extends ViewGroup {
locations = null;
- originalMeasurements = null;
deltas = null;
hasWeightsValid = false;
@@ -2011,7 +2000,6 @@ public class GridLayout extends ViewGroup {
R.styleable.ViewGroup_MarginLayout_layout_marginRight;
private static final int BOTTOM_MARGIN =
R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
-
private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
@@ -2405,7 +2393,7 @@ public class GridLayout extends ViewGroup {
protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
this.flexibility &= spec.getFlexibility();
boolean horizontal = axis.horizontal;
- Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
+ Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal);
// todo test this works correctly when the returned value is UNDEFINED
int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
include(before, size - before);
@@ -2556,6 +2544,16 @@ public class GridLayout extends ViewGroup {
this(startDefined, new Interval(start, start + size), alignment, weight);
}
+ private Alignment getAbsoluteAlignment(boolean horizontal) {
+ if (alignment != UNDEFINED_ALIGNMENT) {
+ return alignment;
+ }
+ if (weight == 0f) {
+ return horizontal ? START : BASELINE;
+ }
+ return FILL;
+ }
+
final Spec copyWriteSpan(Interval span) {
return new Spec(startDefined, span, alignment, weight);
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index f599035..da15302 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -19,6 +19,7 @@ package android.widget;
import com.android.internal.R;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -186,11 +187,11 @@ public class LinearLayout extends ViewGroup {
this(context, null);
}
- public LinearLayout(Context context, AttributeSet attrs) {
+ public LinearLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dd7fa18..a10be11 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
@@ -2263,7 +2264,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param color Sets the text color for all the states (normal, selected,
* focused) to be this color.
*/
- public void setTextColor(int viewId, int color) {
+ public void setTextColor(int viewId, @ColorInt int color) {
setInt(viewId, "setTextColor", color);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 632f5c7..faf1c40 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -637,16 +638,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
this(context, null);
}
- public TextView(Context context, AttributeSet attrs) {
+ public TextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.textViewStyle);
}
- public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@SuppressWarnings("deprecation")
- public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public TextView(
+ Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mText = "";
@@ -2996,7 +2998,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_textColor
*/
@android.view.RemotableViewMethod
- public void setTextColor(int color) {
+ public void setTextColor(@ColorInt int color) {
mTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
@@ -3037,6 +3039,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @return Returns the current text color.
*/
+ @ColorInt
public final int getCurrentTextColor() {
return mCurTextColor;
}
@@ -3047,7 +3050,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_textColorHighlight
*/
@android.view.RemotableViewMethod
- public void setHighlightColor(int color) {
+ public void setHighlightColor(@ColorInt int color) {
if (mHighlightColor != color) {
mHighlightColor = color;
invalidate();
@@ -3061,6 +3064,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textColorHighlight
*/
+ @ColorInt
public int getHighlightColor() {
return mHighlightColor;
}
@@ -3155,6 +3159,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_shadowColor
*/
+ @ColorInt
public int getShadowColor() {
return mShadowColor;
}
@@ -3230,7 +3235,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_textColorHint
*/
@android.view.RemotableViewMethod
- public final void setHintTextColor(int color) {
+ public final void setHintTextColor(@ColorInt int color) {
mHintTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
@@ -3269,6 +3274,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @return Returns the current hint text color.
*/
+ @ColorInt
public final int getCurrentHintTextColor() {
return mHintTextColor != null ? mCurHintTextColor : mCurTextColor;
}
@@ -3282,7 +3288,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_textColorLink
*/
@android.view.RemotableViewMethod
- public final void setLinkTextColor(int color) {
+ public final void setLinkTextColor(@ColorInt int color) {
mLinkTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
@@ -4119,6 +4125,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (type == BufferType.EDITABLE || getKeyListener() != null ||
needEditableForNotification) {
createEditorIfNeeded();
+ mEditor.forgetUndoRedo();
Editable t = mEditableFactory.newEditable(text);
text = t;
setFilters(t, mFilters);
@@ -8098,7 +8105,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
- if (mEditor != null) mEditor.onTouchEvent(event);
+ if (mEditor != null) {
+ mEditor.onTouchEvent(event);
+
+ if (mEditor.mSelectionModifierCursorController != null &&
+ mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {
+ return true;
+ }
+ }
final boolean superResult = super.onTouchEvent(event);
@@ -9104,7 +9118,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return getLayout().getLineForVertical((int) y);
}
- private int getOffsetAtCoordinate(int line, float x) {
+ int getOffsetAtCoordinate(int line, float x) {
x = convertToLocalHorizontalCoordinate(x);
return getLayout().getOffsetForHorizontal(line, x);
}
@@ -9726,4 +9740,4 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
TextView.this.spanChange(buf, what, s, -1, e, -1);
}
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 9bc2aab..d2430bc 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActionBar;
@@ -685,7 +686,7 @@ public class Toolbar extends ViewGroup {
*
* @param color The new text color in 0xAARRGGBB format
*/
- public void setTitleTextColor(int color) {
+ public void setTitleTextColor(@ColorInt int color) {
mTitleTextColor = color;
if (mTitleTextView != null) {
mTitleTextView.setTextColor(color);
@@ -697,7 +698,7 @@ public class Toolbar extends ViewGroup {
*
* @param color The new text color in 0xAARRGGBB format
*/
- public void setSubtitleTextColor(int color) {
+ public void setSubtitleTextColor(@ColorInt int color) {
mSubtitleTextColor = color;
if (mSubtitleTextView != null) {
mSubtitleTextView.setTextColor(color);