summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/animation/AnimatorSet.java7
-rw-r--r--core/java/android/app/Activity.java32
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java39
-rw-r--r--core/java/android/app/AlarmManager.java93
-rw-r--r--core/java/android/app/ApplicationPackageManager.java30
-rw-r--r--core/java/android/app/AssistAction.java277
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java21
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java25
-rw-r--r--core/java/android/app/SystemServiceRegistry.java10
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java13
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl5
-rw-r--r--core/java/android/app/admin/SystemUpdatePolicy.aidl20
-rw-r--r--core/java/android/app/admin/SystemUpdatePolicy.java182
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl4
-rw-r--r--core/java/android/app/usage/UsageStats.java20
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java8
-rw-r--r--core/java/android/app/usage/UsageStatsManagerInternal.java8
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl4
-rw-r--r--core/java/android/content/Context.java25
-rw-r--r--core/java/android/content/Intent.java8
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl9
-rw-r--r--core/java/android/content/pm/LauncherActivityInfo.java55
-rw-r--r--core/java/android/content/pm/PackageManager.java122
-rw-r--r--core/java/android/content/pm/ResolveInfo.java20
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java35
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java110
-rw-r--r--core/java/android/hardware/camera2/legacy/ParameterUtils.java7
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-rw-r--r--core/java/android/net/IpReachabilityMonitor.java354
-rw-r--r--core/java/android/net/netlink/NetlinkConstants.java120
-rw-r--r--core/java/android/net/netlink/NetlinkErrorMessage.java62
-rw-r--r--core/java/android/net/netlink/NetlinkMessage.java97
-rw-r--r--core/java/android/net/netlink/NetlinkSocket.java169
-rw-r--r--core/java/android/net/netlink/RtNetlinkNeighborMessage.java181
-rw-r--r--core/java/android/net/netlink/StructNdMsg.java162
-rw-r--r--core/java/android/net/netlink/StructNdaCacheInfo.java117
-rw-r--r--core/java/android/net/netlink/StructNlAttr.java127
-rw-r--r--core/java/android/net/netlink/StructNlMsgErr.java80
-rw-r--r--core/java/android/net/netlink/StructNlMsgHdr.java137
-rw-r--r--core/java/android/os/IDeviceIdleController.aidl1
-rw-r--r--core/java/android/os/PowerManagerInternal.java2
-rw-r--r--core/java/android/os/storage/IMountService.java26
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/service/chooser/ChooserTarget.java170
-rw-r--r--core/java/android/service/chooser/ChooserTargetService.java2
-rw-r--r--core/java/android/text/DynamicLayout.java10
-rw-r--r--core/java/android/text/Layout.java29
-rw-r--r--core/java/android/text/StaticLayout.java22
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java7
-rw-r--r--core/java/android/view/Choreographer.java2
-rw-r--r--core/java/android/view/Display.aidl19
-rw-r--r--core/java/android/view/Display.java182
-rw-r--r--core/java/android/view/DisplayInfo.java110
-rw-r--r--core/java/android/view/KeyEvent.java2
-rw-r--r--core/java/android/view/View.java40
-rw-r--r--core/java/android/view/ViewGroup.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java32
-rw-r--r--core/java/android/view/WindowManager.java208
-rw-r--r--core/java/android/view/WindowManagerGlobal.java3
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java10
-rw-r--r--core/java/android/webkit/ViewAssistStructure.java203
-rw-r--r--core/java/android/webkit/WebView.java38
-rw-r--r--core/java/android/webkit/WebViewClient.java38
-rw-r--r--core/java/android/webkit/WebViewProvider.java3
-rw-r--r--core/java/android/widget/AppSecurityPermissions.java2
-rw-r--r--core/java/android/widget/Editor.java5
-rw-r--r--core/java/android/widget/Switch.java3
-rw-r--r--core/java/android/widget/TextView.java47
69 files changed, 3148 insertions, 880 deletions
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 6503d89..951fe49 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -16,9 +16,10 @@
package android.animation;
+import android.util.ArrayMap;
+
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
/**
@@ -68,7 +69,7 @@ public final class AnimatorSet extends Animator {
* to a single node representing that Animator, not create a new Node
* if one already exists.
*/
- private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>();
+ private ArrayMap<Animator, Node> mNodeMap = new ArrayMap<Animator, Node>();
/**
* Set of all nodes created for this AnimatorSet. This list is used upon
@@ -646,7 +647,7 @@ public final class AnimatorSet extends Animator {
anim.mTerminated = false;
anim.mStarted = false;
anim.mPlayingSet = new ArrayList<Animator>();
- anim.mNodeMap = new HashMap<Animator, Node>();
+ anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
anim.mSortedNodes = new ArrayList<Node>(nodeCount);
anim.mReversible = mReversible;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9968dbb..49f5099 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3841,10 +3841,7 @@ public class Activity extends ContextThemeWrapper
mStartedActivity = true;
}
- final View decor = mWindow != null ? mWindow.peekDecorView() : null;
- if (decor != null) {
- decor.cancelPendingInputEvents();
- }
+ cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
@@ -3855,6 +3852,18 @@ public class Activity extends ContextThemeWrapper
mParent.startActivityFromChild(this, intent, requestCode);
}
}
+ }
+
+ /**
+ * Cancels pending inputs and if an Activity Transition is to be run, starts the transition.
+ *
+ * @param options The ActivityOptions bundle used to start an Activity.
+ */
+ private void cancelInputsAndStartExitTransition(Bundle options) {
+ final View decor = mWindow != null ? mWindow.peekDecorView() : null;
+ if (decor != null) {
+ decor.cancelPendingInputEvents();
+ }
if (options != null && !isTopOfTask()) {
mActivityTransitionState.startExitOutTransition(this, options);
}
@@ -3872,9 +3881,6 @@ public class Activity extends ContextThemeWrapper
*/
public void startActivityForResultAsUser(Intent intent, int requestCode,
@Nullable Bundle options, UserHandle user) {
- if (options != null) {
- mActivityTransitionState.startExitOutTransition(this, options);
- }
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
@@ -3896,10 +3902,7 @@ public class Activity extends ContextThemeWrapper
mStartedActivity = true;
}
- final View decor = mWindow != null ? mWindow.peekDecorView() : null;
- if (decor != null) {
- decor.cancelPendingInputEvents();
- }
+ cancelInputsAndStartExitTransition(options);
}
/**
@@ -3925,6 +3928,7 @@ public class Activity extends ContextThemeWrapper
mToken, mEmbeddedID, -1, ar.getResultCode(),
ar.getResultData());
}
+ cancelInputsAndStartExitTransition(options);
}
/**
@@ -3948,6 +3952,7 @@ public class Activity extends ContextThemeWrapper
mToken, mEmbeddedID, -1, ar.getResultCode(),
ar.getResultData());
}
+ cancelInputsAndStartExitTransition(options);
}
/**
@@ -4380,6 +4385,7 @@ public class Activity extends ContextThemeWrapper
mToken, child.mEmbeddedID, requestCode,
ar.getResultCode(), ar.getResultData());
}
+ cancelInputsAndStartExitTransition(options);
}
/**
@@ -4431,9 +4437,6 @@ public class Activity extends ContextThemeWrapper
@Override
public void startActivityForResult(
String who, Intent intent, int requestCode, @Nullable Bundle options) {
- if (options != null) {
- mActivityTransitionState.startExitOutTransition(this, options);
- }
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, who,
@@ -4443,6 +4446,7 @@ public class Activity extends ContextThemeWrapper
mToken, who, requestCode,
ar.getResultCode(), ar.getResultData());
}
+ cancelInputsAndStartExitTransition(options);
}
/**
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 968c956..fa81412 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -31,6 +31,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.ViewParent;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.ImageView;
@@ -187,11 +188,6 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
*/
public static final int MSG_SHARED_ELEMENT_DESTINATION = 107;
- /**
- * Send the shared element positions.
- */
- public static final int MSG_SEND_SHARED_ELEMENT_DESTINATION = 108;
-
private Window mWindow;
final protected ArrayList<String> mAllSharedElementNames;
final protected ArrayList<View> mSharedElements = new ArrayList<View>();
@@ -207,6 +203,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
new ArrayList<GhostViewListeners>();
private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>();
private ArrayList<Matrix> mSharedElementParentMatrices;
+ private boolean mSharedElementTransitionComplete;
+ private boolean mViewsTransitionComplete;
public ActivityTransitionCoordinator(Window window,
ArrayList<String> allSharedElementNames,
@@ -219,6 +217,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
}
protected void viewsReady(ArrayMap<String, View> sharedElements) {
+ final View decor = getDecor();
+ final ViewRootImpl viewRoot = decor == null ? null : decor.getViewRootImpl();
+ if (viewRoot != null) {
+ viewRoot.setPausedForTransition(true);
+ }
sharedElements.retainAll(mAllSharedElementNames);
if (mListener != null) {
mListener.onMapSharedElements(mAllSharedElementNames, sharedElements);
@@ -878,6 +881,32 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
}
}
+ protected boolean isViewsTransitionComplete() {
+ return mViewsTransitionComplete;
+ }
+
+ protected void viewsTransitionComplete() {
+ mViewsTransitionComplete = true;
+ startInputWhenTransitionsComplete();
+ }
+
+ protected void sharedElementTransitionComplete() {
+ mSharedElementTransitionComplete = true;
+ startInputWhenTransitionsComplete();
+ }
+ private void startInputWhenTransitionsComplete() {
+ if (mViewsTransitionComplete && mSharedElementTransitionComplete) {
+ final View decor = getDecor();
+ if (decor != null) {
+ final ViewRootImpl viewRoot = decor.getViewRootImpl();
+ viewRoot.setPausedForTransition(false);
+ }
+ onTransitionsComplete();
+ }
+ }
+
+ protected void onTransitionsComplete() {}
+
protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
@Override
public void onTransitionStart(Transition transition) {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index b0fda9c..5e7bd0d 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -71,10 +71,7 @@ import java.io.IOException;
* {@link android.content.Context#getSystemService
* Context.getSystemService(Context.ALARM_SERVICE)}.
*/
-public class AlarmManager
-{
- private static final String TAG = "AlarmManager";
-
+public class AlarmManager {
/**
* Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
* (wall clock time in UTC), which will wake up the device when
@@ -558,7 +555,93 @@ public class AlarmManager
long intervalMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null, null);
}
-
+
+ /**
+ * Like {@link #set(int, long, PendingIntent)}, but this alarm will be allowed to execute
+ * even when the system is in low-power idle modes. This type of alarm must <b>only</b>
+ * be used for situations where it is actually required that the alarm go off while in
+ * idle -- a reasonable example would be for a calendar notification that should make a
+ * sound so the user is aware of it. These alarms can significantly impact the power use
+ * of the device when idle (and thus cause significant battery blame to the app scheduling
+ * them), so they should be used with care.
+ *
+ * <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
+ * out of order with any other alarms, even those from the same app. This will clearly happen
+ * when the device is idle (since this alarm can go off while idle, when any other alarms
+ * from the app will be held until later), but may also happen even when not idle.</p>
+ *
+ * <p>Regardless of the app's target SDK version, this call always allows batching of the
+ * alarm.</p>
+ *
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
+ * @param triggerAtMillis time in milliseconds that the alarm should go
+ * off, using the appropriate clock (depending on the alarm type).
+ * @param operation Action to perform when the alarm goes off;
+ * typically comes from {@link PendingIntent#getBroadcast
+ * IntentSender.getBroadcast()}.
+ *
+ * @see #set(int, long, PendingIntent)
+ * @see #setExactAndAllowWhileIdle
+ * @see #cancel
+ * @see android.content.Context#sendBroadcast
+ * @see android.content.Context#registerReceiver
+ * @see android.content.Intent#filterEquals
+ * @see #ELAPSED_REALTIME
+ * @see #ELAPSED_REALTIME_WAKEUP
+ * @see #RTC
+ * @see #RTC_WAKEUP
+ */
+ public void setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
+ setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE, operation,
+ null, null);
+ }
+
+ /**
+ * Like {@link #setExact(int, long, PendingIntent)}, but this alarm will be allowed to execute
+ * even when the system is in low-power idle modes. If you don't need exact scheduling of
+ * the alarm but still need to execute while idle, consider using
+ * {@link #setAndAllowWhileIdle}. This type of alarm must <b>only</b>
+ * be used for situations where it is actually required that the alarm go off while in
+ * idle -- a reasonable example would be for a calendar notification that should make a
+ * sound so the user is aware of it. These alarms can significantly impact the power use
+ * of the device when idle (and thus cause significant battery blame to the app scheduling
+ * them), so they should be used with care.
+ *
+ * <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
+ * out of order with any other alarms, even those from the same app. This will clearly happen
+ * when the device is idle (since this alarm can go off while idle, when any other alarms
+ * from the app will be held until later), but may also happen even when not idle.
+ * Note that the OS will allow itself more flexibility for scheduling these alarms than
+ * regular exact alarms, since the application has opted into this behavior. When the
+ * device is idle it may take even more liberties with scheduling in order to optimize
+ * for battery life.</p>
+ *
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
+ * @param triggerAtMillis time in milliseconds that the alarm should go
+ * off, using the appropriate clock (depending on the alarm type).
+ * @param operation Action to perform when the alarm goes off;
+ * typically comes from {@link PendingIntent#getBroadcast
+ * IntentSender.getBroadcast()}.
+ *
+ * @see #set
+ * @see #setRepeating
+ * @see #setWindow
+ * @see #cancel
+ * @see android.content.Context#sendBroadcast
+ * @see android.content.Context#registerReceiver
+ * @see android.content.Intent#filterEquals
+ * @see #ELAPSED_REALTIME
+ * @see #ELAPSED_REALTIME_WAKEUP
+ * @see #RTC
+ * @see #RTC_WAKEUP
+ */
+ public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
+ setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, operation,
+ null, null);
+ }
+
/**
* Remove any alarms with a matching {@link Intent}.
* Any alarm, of any type, whose Intent matches this one (as defined by
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 07eee12..04f6430 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -446,18 +446,40 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
- public void grantPermission(String packageName, String permissionName, UserHandle user) {
+ public void grantRuntimePermission(String packageName, String permissionName,
+ UserHandle user) {
+ try {
+ mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String permissionName,
+ UserHandle user) {
+ try {
+ mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
try {
- mPM.grantPermission(packageName, permissionName, user.getIdentifier());
+ return mPM.getPermissionFlags(permissionName, packageName, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
@Override
- public void revokePermission(String packageName, String permissionName, UserHandle user) {
+ public void updatePermissionFlags(String permissionName, String packageName,
+ int flagMask, int flagValues, UserHandle user) {
try {
- mPM.revokePermission(packageName, permissionName, user.getIdentifier());
+ mPM.updatePermissionFlags(permissionName, packageName, flagMask,
+ flagValues, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
diff --git a/core/java/android/app/AssistAction.java b/core/java/android/app/AssistAction.java
deleted file mode 100644
index eb33542..0000000
--- a/core/java/android/app/AssistAction.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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.app;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.TextUtils;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * Helper class for building a {@link Bundle} representing an action being performed by the user,
- * to be included in the Bundle generated by {@link Activity#onProvideAssistData}.
- *
- * @see Activity#onProvideAssistData
- */
-public final class AssistAction {
-
- /**
- * Key name for the Bundle containing the schema.org representation of
- * an action performed, and should be stored in the Bundle generated by
- * {@link Activity#onProvideAssistData}.
- */
- public static final String ASSIST_ACTION_KEY = "android:assist_action";
-
- /** Bundle key to specify the schema.org ID of the content. */
- public static final String KEY_ID = "@id";
-
- /** Bundle key to specify the schema.org type of the content. */
- public static final String KEY_TYPE = "@type";
-
- /** Bundle key to specify the name of the content. */
- public static final String KEY_NAME = "name";
-
- /** Bundle key to specify the description of the content. */
- public static final String KEY_DESCRIPTION = "description";
-
- /** Bundle key to specify the URL of the content. */
- public static final String KEY_URL = "url";
-
- /** Bundle key to specify the object of an action. */
- public static final String KEY_ACTION_OBJECT = "object";
-
- /** Bundle key to specify the action's status. */
- public static final String KEY_ACTION_STATUS = "actionStatus";
-
- /** The act of editing by adding an object to a collection. */
- public static final String TYPE_ADD_ACTION = "AddAction";
-
- /** The act of bookmarking an object. */
- public static final String TYPE_BOOKMARK_ACTION = "BookmarkAction";
-
- /** The act of liking an object. */
- public static final String TYPE_LIKE_ACTION = "LikeAction";
-
- /** The act of consuming audio content. */
- public static final String TYPE_LISTEN_ACTION = "ListenAction";
-
- /** The act of consuming static visual content. */
- public static final String TYPE_VIEW_ACTION = "ViewAction";
-
- /** The act of expressing a desire about the object. */
- public static final String TYPE_WANT_ACTION = "WantAction";
-
- /** The act of watching an object. */
- public static final String TYPE_WATCH_ACTION = "WatchAction";
-
- /** The status of an active action. */
- public static final String STATUS_TYPE_ACTIVE = "ActiveActionStatus";
-
- /** The status of a completed action. */
- public static final String STATUS_TYPE_COMPLETED = "CompletedActionStatus";
-
- private AssistAction() {
- }
-
- /**
- * Update the Bundle passed into {@link Activity#onProvideAssistData} with the action Bundle,
- * built with {@link ActionBuilder}.
- *
- * @param assistDataBundle The Bundle provided to {@link Activity#onProvideAssistData}.
- * @param actionBundle The Bundle representing an schema.org action.
- */
- public static void updateAssistData(Bundle assistDataBundle, Bundle actionBundle) {
- Preconditions.checkNotNull(assistDataBundle);
- Preconditions.checkNotNull(actionBundle);
-
- Preconditions.checkNotNull(actionBundle.getString(KEY_TYPE),
- "The '@type' property is required in the provided actionBundle");
- assistDataBundle.putParcelable(ASSIST_ACTION_KEY, actionBundle);
- }
-
- /**
- * Builds a {@link Bundle} representing a schema.org entity.
- */
- public static final class ThingBuilder {
- private final Bundle mBundle;
-
- public ThingBuilder() {
- mBundle = new Bundle();
- }
-
- /**
- * Sets the name of the content.
- *
- * @param name The name of the content.
- */
- public ThingBuilder setName(@Nullable String name) {
- set(KEY_NAME, name);
- return this;
- }
-
- /**
- * Sets the app URI of the content.
- *
- * @param uri The app URI of the content.
- */
- public ThingBuilder setUrl(@Nullable Uri uri) {
- if (uri != null) {
- set(KEY_URL, uri.toString());
- }
- return this;
- }
-
- /**
- * Sets the ID of the content.
- *
- * @param id Set the ID of the content.
- */
- public ThingBuilder setId(@Nullable String id) {
- set(KEY_ID, id);
- return this;
- }
-
- /**
- * Sets the schema.org type of the content.
- *
- * @param type The schema.org type.
- */
- public ThingBuilder setType(@Nullable String type) {
- set(KEY_TYPE, type);
- return this;
- }
-
- /**
- * Sets the optional description of the content.
- *
- * @param description The description of the content.
- */
- public ThingBuilder setDescription(@Nullable String description) {
- set(KEY_DESCRIPTION, description);
- return this;
- }
-
- /**
- * Sets a property of the content.
- *
- * @param key The schema.org property. Must not be null.
- * @param value The value of the schema.org property.
- * If null, the value will be ignored.
- */
- public ThingBuilder set(@NonNull String key, @Nullable String value) {
- if (value != null) {
- mBundle.putString(key, value);
- }
- return this;
- }
-
- /**
- * Sets a property of the content.
- *
- * @param key The schema.org property. Must not be null.
- * @param value The value of the schema.org property represented as a bundle.
- * If null, the value will be ignored.
- */
- public ThingBuilder set(@NonNull String key, @Nullable Bundle value) {
- if (value != null) {
- mBundle.putParcelable(key, value);
- }
- return this;
- }
-
- /**
- * Build the {@link Bundle} object representing the schema.org entity.
- */
- public Bundle build() {
- return mBundle;
- }
- }
-
- /**
- * Builds a {@link Bundle} representing a schema.org action.
- */
- public static final class ActionBuilder {
- private final Bundle mBundle;
-
- public ActionBuilder() {
- mBundle = new Bundle();
- }
-
- /**
- * Sets the schema.org type of the action.
- *
- * @param type The schema.org type.
- */
- public ActionBuilder setType(@Nullable String type) {
- set(KEY_TYPE, type);
- return this;
- }
-
- /**
- * Sets the schema.org object of the action.
- *
- * @param object The schema.org object of the action.
- */
- public ActionBuilder setObject(@Nullable Bundle object) {
- set(KEY_ACTION_OBJECT, object);
- return this;
- }
-
- /**
- * Sets a property of the action.
- *
- * @param key The schema.org property. Must not be null.
- * @param value The value of the schema.org property.
- * If null, the value will be ignored.
- */
- public ActionBuilder set(@NonNull String key, @Nullable String value) {
- if (value != null) {
- mBundle.putString(key, value);
- }
- return this;
- }
-
- /**
- * Sets a property of the action.
- *
- * @param key The schema.org property. Must not be null.
- * @param value The value of the schema.org property represented as a bundle.
- * If null, the value will be ignored.
- */
- public ActionBuilder set(@NonNull String key, @Nullable Bundle value) {
- if (value != null) {
- mBundle.putParcelable(key, value);
- }
- return this;
- }
-
- /**
- * Build the {@link Bundle} object representing the schema.org action.
- */
- public Bundle build() {
- if (TextUtils.isEmpty(mBundle.getString(KEY_TYPE, null))) {
- // Defaults to the base action type http://schema.org/Action.
- setType("Action");
- }
-
- return mBundle;
- }
- }
-}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index e84a8da..4db4be0 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -55,8 +55,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
private boolean mWasOpaque;
private boolean mAreViewsReady;
private boolean mIsViewsTransitionStarted;
- private boolean mIsViewsTransitionComplete;
- private boolean mIsSharedElementTransitionComplete;
private Transition mEnterViewsTransition;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
@@ -456,7 +454,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
}
}
if (viewsTransition == null) {
- viewTransitionComplete();
+ viewsTransitionComplete();
} else {
viewsTransition.forceVisibility(View.INVISIBLE, true);
final ArrayList<View> transitioningViews = mTransitioningViews;
@@ -474,7 +472,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
public void onTransitionEnd(Transition transition) {
mEnterViewsTransition = null;
transition.removeListener(this);
- viewTransitionComplete();
+ viewsTransitionComplete();
super.onTransitionEnd(transition);
}
});
@@ -497,18 +495,9 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
return transition;
}
- private void viewTransitionComplete() {
- mIsViewsTransitionComplete = true;
- if (mIsSharedElementTransitionComplete) {
- moveSharedElementsFromOverlay();
- }
- }
-
- private void sharedElementTransitionComplete() {
- mIsSharedElementTransitionComplete = true;
- if (mIsViewsTransitionComplete) {
- moveSharedElementsFromOverlay();
- }
+ @Override
+ protected void onTransitionsComplete() {
+ moveSharedElementsFromOverlay();
}
private void sharedElementTransitionStarted() {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 0f286fb..9ddebb0 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -46,8 +46,6 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "ExitTransitionCoordinator";
private static final long MAX_WAIT_MS = 1000;
- private boolean mExitComplete;
-
private Bundle mSharedElementBundle;
private boolean mExitNotified;
@@ -165,7 +163,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
- if (mExitComplete) {
+ if (isViewsTransitionComplete()) {
delayCancel();
}
}
@@ -310,14 +308,14 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
viewsTransition = configureTransition(getViewsTransition(), true);
}
if (viewsTransition == null) {
- exitTransitionComplete();
+ viewsTransitionComplete();
} else {
final ArrayList<View> transitioningViews = mTransitioningViews;
viewsTransition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
- exitTransitionComplete();
+ viewsTransitionComplete();
if (mIsHidden && transitioningViews != null) {
showViews(transitioningViews, true);
}
@@ -373,19 +371,15 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
}
}
- private void exitTransitionComplete() {
- mExitComplete = true;
- notifyComplete();
- }
-
protected boolean isReadyToNotify() {
return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
}
- private void sharedElementTransitionComplete() {
+ @Override
+ protected void sharedElementTransitionComplete() {
mSharedElementBundle = mExitSharedElementBundle == null
? captureSharedElementState() : captureExitSharedElementsState();
- notifyComplete();
+ super.sharedElementTransitionComplete();
}
private Bundle captureExitSharedElementsState() {
@@ -405,6 +399,11 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
return bundle;
}
+ @Override
+ protected void onTransitionsComplete() {
+ notifyComplete();
+ }
+
protected void notifyComplete() {
if (isReadyToNotify()) {
if (!mSharedElementNotified) {
@@ -433,7 +432,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
}
private void notifyExitComplete() {
- if (!mExitNotified && mExitComplete) {
+ if (!mExitNotified && isViewsTransitionComplete()) {
mExitNotified = true;
mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
mResultReceiver = null; // done talking
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 391131a..0d00908 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -55,7 +55,6 @@ import android.location.CountryDetector;
import android.location.ICountryDetector;
import android.location.ILocationManager;
import android.location.LocationManager;
-import android.media.AudioDevicesManager;
import android.media.AudioManager;
import android.media.MediaRouter;
import android.media.midi.IMidiManager;
@@ -701,13 +700,6 @@ final class SystemServiceRegistry {
public RadioManager createService(ContextImpl ctx) {
return new RadioManager(ctx);
}});
-
- registerService(Context.AUDIO_DEVICES_SERVICE, AudioDevicesManager.class,
- new CachedServiceFetcher<AudioDevicesManager>() {
- @Override
- public AudioDevicesManager createService(ContextImpl ctx) {
- return new AudioDevicesManager(ctx);
- }});
}
/**
@@ -726,7 +718,7 @@ final class SystemServiceRegistry {
}
/**
- * Gets the name of the system-level service that is represented by the specified class.
+ * Gets the name of the system-level service that is represented by the specified class.
*/
public static String getSystemServiceName(Class<?> serviceClass) {
return SYSTEM_SERVICE_NAMES.get(serviceClass);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ae07206..3fb7059 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4253,11 +4253,7 @@ public class DevicePolicyManager {
public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) {
if (mService != null) {
try {
- if (policy != null) {
- mService.setSystemUpdatePolicy(who, policy.getPolicyBundle());
- } else {
- mService.setSystemUpdatePolicy(who, null);
- }
+ mService.setSystemUpdatePolicy(who, policy);
} catch (RemoteException re) {
Log.w(TAG, "Error calling setSystemUpdatePolicy", re);
}
@@ -4272,12 +4268,7 @@ public class DevicePolicyManager {
public SystemUpdatePolicy getSystemUpdatePolicy() {
if (mService != null) {
try {
- PersistableBundle bundle = mService.getSystemUpdatePolicy();
- if (bundle != null) {
- return new SystemUpdatePolicy(bundle);
- } else {
- return null;
- }
+ return mService.getSystemUpdatePolicy();
} catch (RemoteException re) {
Log.w(TAG, "Error calling getSystemUpdatePolicy", re);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e81e7c1..481ff62 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,7 @@
package android.app.admin;
+import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -221,8 +222,8 @@ interface IDevicePolicyManager {
void setUserIcon(in ComponentName admin, in Bitmap icon);
void sendDeviceInitializerStatus(int statusCode, String description);
- void setSystemUpdatePolicy(in ComponentName who, in PersistableBundle policy);
- PersistableBundle getSystemUpdatePolicy();
+ void setSystemUpdatePolicy(in ComponentName who, in SystemUpdatePolicy policy);
+ SystemUpdatePolicy getSystemUpdatePolicy();
boolean setKeyguardDisabled(in ComponentName admin, boolean disabled);
boolean setStatusBarDisabled(in ComponentName who, boolean disabled);
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.aidl b/core/java/android/app/admin/SystemUpdatePolicy.aidl
new file mode 100644
index 0000000..58e8d15
--- /dev/null
+++ b/core/java/android/app/admin/SystemUpdatePolicy.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 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.app.admin;
+
+parcelable SystemUpdatePolicy;
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index de56cd0..20ddb77 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -17,8 +17,15 @@
package android.app.admin;
import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PersistableBundle;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -28,7 +35,7 @@ import java.lang.annotation.RetentionPolicy;
* @see DevicePolicyManager#setSystemUpdatePolicy
* @see DevicePolicyManager#getSystemUpdatePolicy
*/
-public class SystemUpdatePolicy {
+public class SystemUpdatePolicy implements Parcelable {
/** @hide */
@IntDef({
@@ -39,6 +46,10 @@ public class SystemUpdatePolicy {
@interface SystemUpdatePolicyType {}
/**
+ * Unknown policy type, used only internally.
+ */
+ private static final int TYPE_UNKNOWN = -1;
+ /**
* Install system update automatically as soon as one is available.
*/
public static final int TYPE_INSTALL_AUTOMATIC = 1;
@@ -63,45 +74,40 @@ public class SystemUpdatePolicy {
private static final String KEY_POLICY_TYPE = "policy_type";
private static final String KEY_INSTALL_WINDOW_START = "install_window_start";
private static final String KEY_INSTALL_WINDOW_END = "install_window_end";
+ /**
+ * The upper boundary of the daily maintenance window: 24 * 60 minutes.
+ */
+ private static final int WINDOW_BOUNDARY = 24 * 60;
- private PersistableBundle mPolicy;
+ @SystemUpdatePolicyType
+ private int mPolicyType;
- public SystemUpdatePolicy() {
- mPolicy = new PersistableBundle();
- }
+ private int mMaintenanceWindowStart;
+ private int mMaintenanceWindowEnd;
- /**
- * Construct an SystemUpdatePolicy object from a bundle.
- * @hide
- */
- public SystemUpdatePolicy(PersistableBundle in) {
- mPolicy = new PersistableBundle(in);
- }
- /**
- * Retrieve the underlying bundle where the policy is stored.
- * @hide
- */
- public PersistableBundle getPolicyBundle() {
- return new PersistableBundle(mPolicy);
+ private SystemUpdatePolicy() {
+ mPolicyType = TYPE_UNKNOWN;
}
/**
- * Set the policy to: install update automatically as soon as one is available.
+ * Create a policy object and set it to install update automatically as soon as one is
+ * available.
*
* @see #TYPE_INSTALL_AUTOMATIC
*/
- public void setAutomaticInstallPolicy() {
- mPolicy.clear();
- mPolicy.putInt(KEY_POLICY_TYPE, TYPE_INSTALL_AUTOMATIC);
+ public static SystemUpdatePolicy createAutomaticInstallPolicy() {
+ SystemUpdatePolicy policy = new SystemUpdatePolicy();
+ policy.mPolicyType = TYPE_INSTALL_AUTOMATIC;
+ return policy;
}
/**
- * Set the policy to: new system update will only be installed automatically when the system
- * clock is inside a daily maintenance window. If the start and end times are the same, the
- * window is considered to include the WHOLE 24 hours, that is, updates can install at any time.
- * If the given window in invalid, a {@link SystemUpdatePolicy.InvalidWindowException} will be
- * thrown. If start time is later than end time, the window is considered spanning midnight,
+ * Create a policy object and set it to: new system update will only be installed automatically
+ * when the system clock is inside a daily maintenance window. If the start and end times are
+ * the same, the window is considered to include the WHOLE 24 hours, that is, updates can
+ * install at any time. If the given window in invalid, a {@link IllegalArgumentException} will
+ * be thrown. If start time is later than end time, the window is considered spanning midnight,
* i.e. end time donates a time on the next day. The maintenance window will last for 30 days,
* after which the system should revert back to its normal behavior as if no policy were set.
*
@@ -111,25 +117,29 @@ public class SystemUpdatePolicy {
* midnight in the device's local time. Must be in the range of [0, 1440).
* @see #TYPE_INSTALL_WINDOWED
*/
- public void setWindowedInstallPolicy(int startTime, int endTime) throws InvalidWindowException{
- if (startTime < 0 || startTime >= 1440 || endTime < 0 || endTime >= 1440) {
- throw new InvalidWindowException("startTime and endTime must be inside [0, 1440)");
+ public static SystemUpdatePolicy createWindowedInstallPolicy(int startTime, int endTime) {
+ if (startTime < 0 || startTime >= WINDOW_BOUNDARY
+ || endTime < 0 || endTime >= WINDOW_BOUNDARY) {
+ throw new IllegalArgumentException("startTime and endTime must be inside [0, 1440)");
}
- mPolicy.clear();
- mPolicy.putInt(KEY_POLICY_TYPE, TYPE_INSTALL_WINDOWED);
- mPolicy.putInt(KEY_INSTALL_WINDOW_START, startTime);
- mPolicy.putInt(KEY_INSTALL_WINDOW_END, endTime);
+ SystemUpdatePolicy policy = new SystemUpdatePolicy();
+ policy.mPolicyType = TYPE_INSTALL_WINDOWED;
+ policy.mMaintenanceWindowStart = startTime;
+ policy.mMaintenanceWindowEnd = endTime;
+ return policy;
}
/**
- * Set the policy to: block installation for a maximum period of 30 days. After expiration the
- * system should revert back to its normal behavior as if no policy were set.
+ * Create a policy object and set it to block installation for a maximum period of 30 days.
+ * After expiration the system should revert back to its normal behavior as if no policy were
+ * set.
*
* @see #TYPE_POSTPONE
*/
- public void setPostponeInstallPolicy() {
- mPolicy.clear();
- mPolicy.putInt(KEY_POLICY_TYPE, TYPE_POSTPONE);
+ public static SystemUpdatePolicy createPostponeInstallPolicy() {
+ SystemUpdatePolicy policy = new SystemUpdatePolicy();
+ policy.mPolicyType = TYPE_POSTPONE;
+ return policy;
}
/**
@@ -140,7 +150,7 @@ public class SystemUpdatePolicy {
*/
@SystemUpdatePolicyType
public int getPolicyType() {
- return mPolicy.getInt(KEY_POLICY_TYPE, -1);
+ return mPolicyType;
}
/**
@@ -150,8 +160,8 @@ public class SystemUpdatePolicy {
* or -1 if the policy does not have a maintenance window.
*/
public int getInstallWindowStart() {
- if (getPolicyType() == TYPE_INSTALL_WINDOWED) {
- return mPolicy.getInt(KEY_INSTALL_WINDOW_START, -1);
+ if (mPolicyType == TYPE_INSTALL_WINDOWED) {
+ return mMaintenanceWindowStart;
} else {
return -1;
}
@@ -164,26 +174,98 @@ public class SystemUpdatePolicy {
* or -1 if the policy does not have a maintenance window.
*/
public int getInstallWindowEnd() {
- if (getPolicyType() == TYPE_INSTALL_WINDOWED) {
- return mPolicy.getInt(KEY_INSTALL_WINDOW_END, -1);
+ if (mPolicyType == TYPE_INSTALL_WINDOWED) {
+ return mMaintenanceWindowEnd;
} else {
return -1;
}
}
+ /**
+ * Return if this object represents a valid policy.
+ * @hide
+ */
+ public boolean isValid() {
+ if (mPolicyType == TYPE_INSTALL_AUTOMATIC || mPolicyType == TYPE_POSTPONE) {
+ return true;
+ } else if (mPolicyType == TYPE_INSTALL_WINDOWED) {
+ return mMaintenanceWindowStart >= 0 && mMaintenanceWindowStart < WINDOW_BOUNDARY
+ && mMaintenanceWindowEnd >= 0 && mMaintenanceWindowEnd < WINDOW_BOUNDARY;
+ } else {
+ return false;
+ }
+ }
+
@Override
public String toString() {
- return mPolicy.toString();
+ return String.format("SystemUpdatePolicy (type: %d, windowStart: %d, windowEnd: %d)",
+ mPolicyType, mMaintenanceWindowStart, mMaintenanceWindowEnd);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
}
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPolicyType);
+ dest.writeInt(mMaintenanceWindowStart);
+ dest.writeInt(mMaintenanceWindowEnd);
+ }
+
+ public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR =
+ new Parcelable.Creator<SystemUpdatePolicy>() {
+
+ @Override
+ public SystemUpdatePolicy createFromParcel(Parcel source) {
+ SystemUpdatePolicy policy = new SystemUpdatePolicy();
+ policy.mPolicyType = source.readInt();
+ policy.mMaintenanceWindowStart = source.readInt();
+ policy.mMaintenanceWindowEnd = source.readInt();
+ return policy;
+ }
+
+ @Override
+ public SystemUpdatePolicy[] newArray(int size) {
+ return new SystemUpdatePolicy[size];
+ }
+ };
+
+
/**
- * Exception thrown by {@link SystemUpdatePolicy#setWindowedInstallPolicy(int, int)} in case the
- * specified window is invalid.
+ * @hide
*/
- public static class InvalidWindowException extends Exception {
- public InvalidWindowException(String reason) {
- super(reason);
+ public static SystemUpdatePolicy restoreFromXml(XmlPullParser parser) {
+ try {
+ SystemUpdatePolicy policy = new SystemUpdatePolicy();
+ String value = parser.getAttributeValue(null, KEY_POLICY_TYPE);
+ if (value != null) {
+ policy.mPolicyType = Integer.parseInt(value);
+
+ value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_START);
+ if (value != null) {
+ policy.mMaintenanceWindowStart = Integer.parseInt(value);
+ }
+ value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_END);
+ if (value != null) {
+ policy.mMaintenanceWindowEnd = Integer.parseInt(value);
+ }
+ return policy;
+ }
+ } catch (NumberFormatException e) {
+ // Fail through
}
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ public void saveToXml(XmlSerializer out) throws IOException {
+ out.attribute(null, KEY_POLICY_TYPE, Integer.toString(mPolicyType));
+ out.attribute(null, KEY_INSTALL_WINDOW_START, Integer.toString(mMaintenanceWindowStart));
+ out.attribute(null, KEY_INSTALL_WINDOW_END, Integer.toString(mMaintenanceWindowEnd));
}
}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 23659e3..254408a 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -30,6 +30,6 @@ interface IUsageStatsManager {
ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime,
String callingPackage);
UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
- void setAppIdle(String packageName, boolean idle, int userId);
- boolean isAppIdle(String packageName, int userId);
+ void setAppInactive(String packageName, boolean inactive, int userId);
+ boolean isAppInactive(String packageName, int userId);
}
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index abfc435..81c7422 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -46,6 +46,13 @@ public final class UsageStats implements Parcelable {
public long mLastTimeUsed;
/**
+ * Last time the package was used and the beginning of the idle countdown.
+ * This uses a different timebase that is about how much the device has been in use in general.
+ * {@hide}
+ */
+ public long mBeginIdleTime;
+
+ /**
* {@hide}
*/
public long mTotalTimeInForeground;
@@ -74,6 +81,7 @@ public final class UsageStats implements Parcelable {
mTotalTimeInForeground = stats.mTotalTimeInForeground;
mLaunchCount = stats.mLaunchCount;
mLastEvent = stats.mLastEvent;
+ mBeginIdleTime = stats.mBeginIdleTime;
}
public String getPackageName() {
@@ -110,6 +118,15 @@ public final class UsageStats implements Parcelable {
}
/**
+ * @hide
+ * Get the last time this package was active, measured in milliseconds. This timestamp
+ * uses a timebase that represents how much the device was used and not wallclock time.
+ */
+ public long getBeginIdleTime() {
+ return mBeginIdleTime;
+ }
+
+ /**
* Get the total time this package spent in the foreground, measured in milliseconds.
*/
public long getTotalTimeInForeground() {
@@ -133,6 +150,7 @@ public final class UsageStats implements Parcelable {
mLastEvent = right.mLastEvent;
mEndTimeStamp = right.mEndTimeStamp;
mLastTimeUsed = right.mLastTimeUsed;
+ mBeginIdleTime = right.mBeginIdleTime;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
@@ -153,6 +171,7 @@ public final class UsageStats implements Parcelable {
dest.writeLong(mTotalTimeInForeground);
dest.writeInt(mLaunchCount);
dest.writeInt(mLastEvent);
+ dest.writeLong(mBeginIdleTime);
}
public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@@ -166,6 +185,7 @@ public final class UsageStats implements Parcelable {
stats.mTotalTimeInForeground = in.readLong();
stats.mLaunchCount = in.readInt();
stats.mLastEvent = in.readInt();
+ stats.mBeginIdleTime = in.readLong();
return stats;
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 8a01d66..c74bbdd 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -220,15 +220,15 @@ public final class UsageStatsManager {
}
/**
- * Returns whether the specified app is currently considered idle. This will be true if the
+ * Returns whether the specified app is currently considered inactive. This will be true if the
* app hasn't been used directly or indirectly for a period of time defined by the system. This
* could be of the order of several hours or days.
* @param packageName The package name of the app to query
- * @return whether the app is currently considered idle
+ * @return whether the app is currently considered inactive
*/
- public boolean isAppIdle(String packageName) {
+ public boolean isAppInactive(String packageName) {
try {
- return mService.isAppIdle(packageName, UserHandle.myUserId());
+ return mService.isAppInactive(packageName, UserHandle.myUserId());
} catch (RemoteException e) {
// fall through and return default
}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 8b3fc2e..7bcc038 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -69,14 +69,6 @@ public abstract class UsageStatsManagerInternal {
public abstract boolean isAppIdle(String packageName, int userId);
/**
- * Returns the most recent time that the specified package was active for the given user.
- * @param packageName The package to search.
- * @param userId The user id of the user of interest.
- * @return The timestamp of when the package was last used, or -1 if it hasn't been used.
- */
- public abstract long getLastPackageAccessTime(String packageName, int userId);
-
- /**
* Sets up a listener for changes to packages being accessed.
* @param listener A listener within the system process.
*/
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a3eceb5..7a894ae 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -101,8 +101,8 @@ interface IBluetooth
void getActivityEnergyInfoFromController();
BluetoothActivityEnergyInfo reportActivityInfo();
- // for dumpsys support
- String dump();
+ // For dumpsys support
+ void dump(in ParcelFileDescriptor fd);
void onLeServiceUp();
void onBrEdrDown();
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8687c6b..a434c7b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -134,7 +134,15 @@ public abstract class Context {
* explicitly set if desired.
*
* @see #getSharedPreferences
+ *
+ * @deprecated MODE_MULTI_PROCESS does not work reliably in
+ * some versions of Android, and furthermore does not provide any
+ * mechanism for reconciling concurrent modifications across
+ * processes. Applications should not attempt to use it. Instead,
+ * they should use an explicit cross-process data management
+ * approach such as {@link android.content.ContentProvider ContentProvider}.
*/
+ @Deprecated
public static final int MODE_MULTI_PROCESS = 0x0004;
/**
@@ -604,11 +612,7 @@ public abstract class Context {
* editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
* @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
* default operation, {@link #MODE_WORLD_READABLE}
- * and {@link #MODE_WORLD_WRITEABLE} to control permissions. The bit
- * {@link #MODE_MULTI_PROCESS} can also be used if multiple processes
- * are mutating the same SharedPreferences file. {@link #MODE_MULTI_PROCESS}
- * is always on in apps targeting Gingerbread (Android 2.3) and below, and
- * off by default in later versions.
+ * and {@link #MODE_WORLD_WRITEABLE} to control permissions.
*
* @return The single {@link SharedPreferences} instance that can be used
* to retrieve and modify the preference values.
@@ -616,7 +620,6 @@ public abstract class Context {
* @see #MODE_PRIVATE
* @see #MODE_WORLD_READABLE
* @see #MODE_WORLD_WRITEABLE
- * @see #MODE_MULTI_PROCESS
*/
public abstract SharedPreferences getSharedPreferences(String name,
int mode);
@@ -3133,16 +3136,6 @@ public abstract class Context {
public static final String RADIO_SERVICE = "radio";
/**
- * Use with {@link #getSystemService} to retrieve a
- * {@link android.media.AudioDevicesManager} for handling device enumeration & notification.
- *
- * @see #getSystemService
- * @see android.media.AudioDevicesManager
- */
- public static final String AUDIO_DEVICES_SERVICE = "audio_devices_manager";
-
-
- /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6f543a8..7d76760 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3365,14 +3365,6 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
/**
- * A Parcelable[] of {@link android.service.chooser.ChooserTarget ChooserTarget} objects
- * as set with {@link #putExtra(String, Parcelable[])} representing additional app-specific
- * targets to place at the front of the list of choices. Shown to the user with
- * {@link #ACTION_CHOOSER}.
- */
- public static final String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
-
- /**
* A Bundle forming a mapping of potential target package names to different extras Bundles
* to add to the default intent extras in {@link #EXTRA_INTENT} when used with
* {@link #ACTION_CHOOSER}. Each key should be a package name. The package need not
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 94b0223..ddff782 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -96,9 +96,14 @@ interface IPackageManager {
void removePermission(String name);
- void grantPermission(String packageName, String permissionName, int userId);
+ void grantRuntimePermission(String packageName, String permissionName, int userId);
- void revokePermission(String packageName, String permissionName, int userId);
+ void revokeRuntimePermission(String packageName, String permissionName, int userId);
+
+ int getPermissionFlags(String permissionName, String packageName, int userId);
+
+ void updatePermissionFlags(String permissionName, String packageName, int flagMask,
+ int flagValues, int userId);
boolean isProtectedBroadcast(String actionName);
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 87b97aa..6827d7a 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -103,20 +103,30 @@ public class LauncherActivityInfo {
* density DPI values from {@link DisplayMetrics}.
* @see #getBadgedIcon(int)
* @see DisplayMetrics
- * @return The drawable associated with the activity
+ * @return The drawable associated with the activity.
*/
public Drawable getIcon(int density) {
- int iconRes = mResolveInfo.getIconResource();
- Resources resources = null;
- Drawable icon = null;
- // Get the preferred density icon from the app's resources
- if (density != 0 && iconRes != 0) {
- try {
- resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
- icon = resources.getDrawableForDensity(iconRes, density);
- } catch (NameNotFoundException | Resources.NotFoundException exc) {
- }
+ final int iconRes = mResolveInfo.getIconResource();
+ Drawable icon = getDrawableForDensity(iconRes, density);
+ // Get the default density icon
+ if (icon == null) {
+ icon = mResolveInfo.loadIcon(mPm);
}
+ return icon;
+ }
+
+ /**
+ * Returns the icon for this activity, without any badging for the profile.
+ * This function can get the icon no matter the icon needs to be badged or not.
+ * @param density The preferred density of the icon, zero for default density. Use
+ * density DPI values from {@link DisplayMetrics}.
+ * @see #getBadgedIcon(int)
+ * @see DisplayMetrics
+ * @return The drawable associated with the activity.
+ */
+ private Drawable getOriginalIcon(int density) {
+ final int iconRes = mResolveInfo.getIconResourceInternal();
+ Drawable icon = getDrawableForDensity(iconRes, density);
// Get the default density icon
if (icon == null) {
icon = mResolveInfo.loadIcon(mPm);
@@ -125,6 +135,27 @@ public class LauncherActivityInfo {
}
/**
+ * Returns the drawable for this activity, without any badging for the profile.
+ * @param resource id of the drawable.
+ * @param density The preferred density of the icon, zero for default density. Use
+ * density DPI values from {@link DisplayMetrics}.
+ * @see DisplayMetrics
+ * @return The drawable associated with the resource id.
+ */
+ private Drawable getDrawableForDensity(int iconRes, int density) {
+ // Get the preferred density icon from the app's resources
+ if (density != 0 && iconRes != 0) {
+ try {
+ final Resources resources
+ = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+ return resources.getDrawableForDensity(iconRes, density);
+ } catch (NameNotFoundException | Resources.NotFoundException exc) {
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the application flags from the ApplicationInfo of the activity.
*
* @return Application flags
@@ -167,7 +198,7 @@ public class LauncherActivityInfo {
* @return A badged icon for the activity.
*/
public Drawable getBadgedIcon(int density) {
- Drawable originalIcon = getIcon(density);
+ Drawable originalIcon = getOriginalIcon(density);
if (originalIcon instanceof BitmapDrawable) {
return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 51fa075..202a8a7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1888,6 +1888,65 @@ public abstract class PackageManager {
public static final String EXTRA_FAILURE_EXISTING_PERMISSION
= "android.content.pm.extra.FAILURE_EXISTING_PERMISSION";
+ /**
+ * Permission flag: The permission is set in its current state
+ * by the user and apps can still request it at runtime.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_USER_SET = 1 << 0;
+
+ /**
+ * Permission flag: The permission is set in its current state
+ * by the user and it is fixed, i.e. apps can no longer request
+ * this permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_USER_FIXED = 1 << 1;
+
+ /**
+ * Permission flag: The permission is set in its current state
+ * by device policy and neither apps nor the user can change
+ * its state.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_POLICY_FIXED = 1 << 2;
+
+ /**
+ * Permission flag: The permission is set in a granted state but
+ * access to resources it guards is restricted by other means to
+ * enable revoking a permission on legacy apps that do not support
+ * runtime permissions. If this permission is upgraded to runtime
+ * because the app was updated to support runtime permissions, the
+ * the permission will be revoked in the upgrade process.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3;
+
+ /**
+ * Permission flag: The permission is set in its current state
+ * because the app is a component that is a part of the system.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_SYSTEM_FIXED = 1 << 4;
+
+ /**
+ * Mask for all permission flags.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int MASK_PERMISSION_FLAGS = 0xFF;
+
/**
* Retrieve overall information about an application package that is
* installed on the system.
@@ -2374,6 +2433,21 @@ public abstract class PackageManager {
*/
public abstract void removePermission(String name);
+
+ /**
+ * Permission flags set when granting or revoking a permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @IntDef({FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_POLICY_FIXED,
+ FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ FLAG_PERMISSION_SYSTEM_FIXED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionFlags {}
+
/**
* Grant a runtime permission to an application which the application does not
* already have. The permission must have been requested by the application.
@@ -2389,19 +2463,20 @@ public abstract class PackageManager {
* @param permissionName The permission name to grant.
* @param user The user for which to grant the permission.
*
- * @see #revokePermission(String, String, android.os.UserHandle)
+ * @see #revokeRuntimePermission(String, String, android.os.UserHandle)
+ * @see android.content.pm.PackageManager.PermissionFlags
*
* @hide
*/
@SystemApi
- public abstract void grantPermission(@NonNull String packageName,
+ public abstract void grantRuntimePermission(@NonNull String packageName,
@NonNull String permissionName, @NonNull UserHandle user);
/**
* Revoke a runtime permission that was previously granted by {@link
- * #grantPermission(String, String, android.os.UserHandle)}. The permission
- * must have been requested by and granted to the application. If the
- * application is not allowed to hold the permission, a {@link
+ * #grantRuntimePermission(String, String, android.os.UserHandle)}. The
+ * permission must have been requested by and granted to the application.
+ * If the application is not allowed to hold the permission, a {@link
* java.lang.SecurityException} is thrown.
* <p>
* <strong>Note: </strong>Using this API requires holding
@@ -2413,15 +2488,47 @@ public abstract class PackageManager {
* @param permissionName The permission name to revoke.
* @param user The user for which to revoke the permission.
*
- * @see #grantPermission(String, String, android.os.UserHandle)
+ * @see #grantRuntimePermission(String, String, android.os.UserHandle)
+ * @see android.content.pm.PackageManager.PermissionFlags
*
* @hide
*/
@SystemApi
- public abstract void revokePermission(@NonNull String packageName,
+ public abstract void revokeRuntimePermission(@NonNull String packageName,
@NonNull String permissionName, @NonNull UserHandle user);
/**
+ * Gets the state flags associated with a permission.
+ *
+ * @param permissionName The permission for which to get the flags.
+ * @param packageName The package name for which to get the flags.
+ * @param user The user for which to get permission flags.
+ * @return The permission flags.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract @PermissionFlags int getPermissionFlags(String permissionName,
+ String packageName, @NonNull UserHandle user);
+
+ /**
+ * Updates the flags associated with a permission by replacing the flags in
+ * the specified mask with the provided flag values.
+ *
+ * @param permissionName The permission for which to update the flags.
+ * @param packageName The package name for which to update the flags.
+ * @param flagMask The flags which to replace.
+ * @param flagValues The flags with which to replace.
+ * @param user The user for which to update the permission flags.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract void updatePermissionFlags(String permissionName,
+ String packageName, @PermissionFlags int flagMask, int flagValues,
+ @NonNull UserHandle user);
+
+ /**
* Returns an {@link android.content.Intent} suitable for passing to
* {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
* which prompts the user to grant permissions to this application.
@@ -3632,6 +3739,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SystemApi
public abstract void verifyIntentFilter(int verificationId, int verificationCode,
List<String> outFailedDomains);
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 05f5e90..649fdb4 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -221,16 +221,16 @@ public class ResolveInfo implements Parcelable {
}
return ci.loadIcon(pm);
}
-
+
/**
* Return the icon resource identifier to use for this match. If the
* match defines an icon, that is used; else if the activity defines
* an icon, that is used; else, the application icon is used.
- *
+ * This function does not check noResourceId flag.
+ *
* @return The icon associated with this match.
*/
- public final int getIconResource() {
- if (noResourceId) return 0;
+ final int getIconResourceInternal() {
if (icon != 0) return icon;
final ComponentInfo ci = getComponentInfo();
if (ci != null) {
@@ -239,6 +239,18 @@ public class ResolveInfo implements Parcelable {
return 0;
}
+ /**
+ * Return the icon resource identifier to use for this match. If the
+ * match defines an icon, that is used; else if the activity defines
+ * an icon, that is used; else, the application icon is used.
+ *
+ * @return The icon associated with this match.
+ */
+ public final int getIconResource() {
+ if (noResourceId) return 0;
+ return getIconResourceInternal();
+ }
+
public void dump(Printer pw, String prefix) {
if (filter != null) {
pw.println(prefix + "Filter:");
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index ef71c42..f70e075 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -177,13 +177,16 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* was explicitly closed, a new session has been created
* or the camera device has been closed.
* @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not
- * configured as outputs for this session; or a reprocess
- * capture request is submitted in a non-reprocessible capture
- * session; or the reprocess capture request was created with
- * a {@link TotalCaptureResult} from a different session; or
- * the capture targets a Surface in the middle of being
- * {@link #prepare prepared}; or the handler is null, the
- * listener is not null, and the calling thread has no looper.
+ * configured as outputs for this session; or the request
+ * targets a set of Surfaces that cannot be submitted
+ * simultaneously in a reprocessible capture session; or a
+ * reprocess capture request is submitted in a
+ * non-reprocessible capture session; or the reprocess capture
+ * request was created with a {@link TotalCaptureResult} from
+ * a different session; or the capture targets a Surface in
+ * the middle of being {@link #prepare prepared}; or the
+ * handler is null, the listener is not null, and the calling
+ * thread has no looper.
*
* @see #captureBurst
* @see #setRepeatingRequest
@@ -233,14 +236,16 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* was explicitly closed, a new session has been created
* or the camera device has been closed.
* @throws IllegalArgumentException If the requests target no Surfaces, or the requests target
- * Surfaces not currently configured as outputs; or a reprocess
- * capture request is submitted in a non-reprocessible capture
- * session; or one of the reprocess capture requests was
- * created with a {@link TotalCaptureResult} from a different
- * session; or one of the captures targets a Surface in the
- * middle of being {@link #prepare prepared}; or if the handler
- * is null, the listener is not null, and the calling thread
- * has no looper.
+ * Surfaces not currently configured as outputs; or one of the
+ * requests targets a set of Surfaces that cannot be submitted
+ * simultaneously in a reprocessible capture session; or a
+ * reprocess capture request is submitted in a
+ * non-reprocessible capture session; or one of the reprocess
+ * capture requests was created with a
+ * {@link TotalCaptureResult} from a different session; or one
+ * of the captures targets a Surface in the middle of being
+ * {@link #prepare prepared}; or if the handler is null, the
+ * listener is not null, and the calling thread has no looper.
*
* @see #capture
* @see #setRepeatingRequest
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index e9564b3..4af7daf 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -416,24 +416,27 @@ public abstract class CameraDevice implements AutoCloseable {
* ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING}) or OPAQUE
* reprocessing
* ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING}), besides
- * the capture session created via {@link #createCaptureSession}, the application can also
- * create a reprocessible capture session to submit reprocess capture requests in addition to
- * regular capture requests. A reprocess capture request takes the next available buffer from
- * the session's input Surface, and sends it through the camera device's processing pipeline
- * again, to produce buffers for the request's target output Surfaces. No new image data is
- * captured for a reprocess request. However the input buffer provided by
+ * the capture session created via {@link #createCaptureSession createCaptureSession}, the
+ * application can also create a reprocessible capture session to submit reprocess capture
+ * requests in addition to regular capture requests. A reprocess capture request takes the next
+ * available buffer from the session's input Surface, and sends it through the camera device's
+ * processing pipeline again, to produce buffers for the request's target output Surfaces. No
+ * new image data is captured for a reprocess request. However the input buffer provided by
* the application must be captured previously by the same camera device in the same session
* directly (e.g. for Zero-Shutter-Lag use case) or indirectly (e.g. combining multiple output
* images).</p>
*
* <p>The active reprocessible capture session determines an input {@link Surface} and the set
* of potential output Surfaces for the camera devices for each capture request. The application
- * can use {@link #createCaptureRequest} to create regular capture requests to capture new
- * images from the camera device, and use {@link #createReprocessCaptureRequest} to create
- * reprocess capture requests to process buffers from the input {@link Surface}. A request may
- * use all or only some of the outputs. All the output Surfaces in one capture request will come
- * from the same source, either from a new capture by the camera device, or from the input
- * Surface depending on if the request is a reprocess capture request.</p>
+ * can use {@link #createCaptureRequest createCaptureRequest} to create regular capture requests
+ * to capture new images from the camera device, and use {@link #createReprocessCaptureRequest
+ * createReprocessCaptureRequest} to create reprocess capture requests to process buffers from
+ * the input {@link Surface}. Some combinations of output Surfaces in a session may not be used
+ * in a request simultaneously. The guaranteed combinations of output Surfaces that can be used
+ * in a request simultaneously are listed in the tables under {@link #createCaptureSession
+ * createCaptureSession}. All the output Surfaces in one capture request will come from the
+ * same source, either from a new capture by the camera device, or from the input Surface
+ * depending on if the request is a reprocess capture request.</p>
*
* <p>Input formats and sizes supported by the camera device can be queried via
* {@link StreamConfigurationMap#getInputFormats} and
@@ -451,6 +454,88 @@ public abstract class CameraDevice implements AutoCloseable {
* {@link android.graphics.ImageFormat#PRIVATE} format. Otherwise, creating a reprocessible
* capture session will fail.</p>
*
+ * <p>The guaranteed stream configurations listed in
+ * {@link #createCaptureSession createCaptureSession} are also guaranteed to work for
+ * {@link #createReprocessibleCaptureSession createReprocessibleCaptureSession}. In addition,
+ * the configurations in the tables below are also guaranteed for creating a reprocessible
+ * capture session if the camera device supports YUV reprocessing or OPAQUE reprocessing.
+ * However, not all output targets used to create a reprocessible session may be used in a
+ * {@link CaptureRequest} simultaneously. The guaranteed output targets that can be included
+ * in a {@link CaptureRequest} simultaneously are listed in the tables under
+ * {@link #createCaptureSession createCaptureSession}. For example, with a FULL-capability
+ * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} {@code == }
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) device that supports OPAQUE
+ * reprocessing, an application can create a reprocessible capture session with 1 input,
+ * ({@code PRIV}, {@code MAXIMUM}), and 3 outputs, ({@code PRIV}, {@code MAXIMUM}),
+ * ({@code PRIV}, {@code PREVIEW}), and ({@code YUV}, {@code MAXIMUM}). However, it's not
+ * guaranteed that an application can submit a regular or reprocess capture with ({@code PRIV},
+ * {@code MAXIMUM}) and ({@code YUV}, {@code MAXIMUM}) outputs based on the table listed under
+ * {@link #createCaptureSession createCaptureSession}. In other words, use the tables below to
+ * determine the guaranteed stream configurations for creating a reprocessible capture session,
+ * and use the tables under {@link #createCaptureSession createCaptureSession} to determine the
+ * guaranteed output targets that can be submitted in a regular or reprocess
+ * {@link CaptureRequest} simultaneously.</p>
+ *
+ * <style scoped>
+ * #rb { border-right-width: thick; }
+ * </style>
+ *
+ * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
+ * support at least the following stream combinations for creating a reprocessible capture
+ * session in addition to those listed in {@link #createCaptureSession createCaptureSession} for
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
+ *
+ * <table>
+ * <tr><th colspan="11">LIMITED-level additional guaranteed configurations for creating a reprocessible capture session<br>({@code PRIV} input is guaranteed only if OPAQUE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>No-viewfinder still image reprocessing.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>ZSL(Zero-Shutter-Lag) still imaging.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>ZSL still and in-app processing imaging.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>ZSL in-app processing with still capture.</td> </tr>
+ * </table><br>
+ * </p>
+ *
+ * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
+ * support at least the following stream combinations for creating a reprocessible capture
+ * session in addition to those for
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
+ *
+ * <table>
+ * <tr><th colspan="11">FULL-capability additional guaranteed configurations for creating a reprocessible capture session<br>({@code PRIV} input is guaranteed only if OPAQUE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>Maximum-resolution multi-frame image fusion in-app processing with regular preview.</td> </tr>
+ * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>Maximum-resolution multi-frame image fusion two-input in-app processing.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code RECORD}</td> <td></td><td id="rb"></td> <td>High-resolution ZSL in-app video processing with regular preview.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>Maximum-resolution ZSL in-app processing with regular preview.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>Maximum-resolution two-input ZSL in-app processing.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code RECORD}</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD}</td> <td>High-resolution ZSL in-app video processing and video snapshot with regular preview.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Maximum-resolution two-input ZSL in-app processing with regular preview.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>ZSL still capture and in-app processing.</td> </tr>
+ * </table><br>
+ * </p>
+ *
+ * <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support
+ * at least the following stream combinations for creating a reprocessible capture session
+ * on both {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices
+ *
+ * <table>
+ * <tr><th colspan="11">RAW-capability additional guaranteed configurations for creating a reprocessible capture session<br>({@code PRIV} input is guaranteed only if OPAQUE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>Mutually exclusive ZSL in-app processing and DNG capture.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>Mutually exclusive ZSL in-app processing and preview with DNG capture.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>Mutually exclusive ZSL two-input in-app processing and DNG capture.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>Mutually exclusive ZSL still capture and preview with DNG capture.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>Mutually exclusive ZSL in-app processing with still capture and DNG capture.</td> </tr>
+ * </table><br>
+ * </p>
+ *
* @param inputConfig The configuration for the input {@link Surface}
* @param outputs The new set of Surfaces that should be made available as
* targets for captured image data.
@@ -466,6 +551,7 @@ public abstract class CameraDevice implements AutoCloseable {
* encountered a fatal error
* @throws IllegalStateException if the camera device has been closed
*
+ * @see #createCaptureSession
* @see CameraCaptureSession
* @see StreamConfigurationMap#getInputFormats
* @see StreamConfigurationMap#getInputSizes
diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
index 9e9a6fe..32bbc51 100644
--- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java
+++ b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
@@ -61,6 +61,8 @@ public class ParameterUtils {
public static final Rect RECTANGLE_EMPTY =
new Rect(/*left*/0, /*top*/0, /*right*/0, /*bottom*/0);
+ private static final double ASPECT_RATIO_TOLERANCE = 0.05f;
+
/**
* Calculate effective/reported zoom data from a user-specified crop region.
*/
@@ -498,7 +500,10 @@ public class ParameterUtils {
float aspectRatioPreview = previewSize.getWidth() * 1.0f / previewSize.getHeight();
float cropH, cropW;
- if (aspectRatioPreview < aspectRatioArray) {
+ if (Math.abs(aspectRatioPreview - aspectRatioArray) < ASPECT_RATIO_TOLERANCE) {
+ cropH = activeArray.height();
+ cropW = activeArray.width();
+ } else if (aspectRatioPreview < aspectRatioArray) {
// The new width must be smaller than the height, so scale the width by AR
cropH = activeArray.height();
cropW = cropH * aspectRatioPreview;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 02793f1..aa697ea 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -125,11 +125,13 @@ public abstract class DisplayManagerInternal {
* mirroring.
* @param requestedRefreshRate The preferred refresh rate for the top-most visible window that
* has a preference.
+ * @param requestedModeId The preferred mode id for the top-most visible window that has a
+ * preference.
* @param inTraversal True if called from WindowManagerService during a window traversal
* prior to call to performTraversalInTransactionFromWindowManager.
*/
public abstract void setDisplayProperties(int displayId, boolean hasContent,
- float requestedRefreshRate, boolean inTraversal);
+ float requestedRefreshRate, int requestedModeId, boolean inTraversal);
/**
* Applies an offset to the contents of a display, for example to avoid burn-in.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d8c3361..26878c0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -496,6 +496,8 @@ public class ConnectivityManager {
* Tests if a given integer represents a valid network type.
* @param networkType the type to be tested
* @return a boolean. {@code true} if the type is valid, else {@code false}
+ * @deprecated All APIs accepting a network type are deprecated. There should be no need to
+ * validate a network type.
*/
public static boolean isNetworkTypeValid(int networkType) {
return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java
new file mode 100644
index 0000000..7e1c05b
--- /dev/null
+++ b/core/java/android/net/IpReachabilityMonitor.java
@@ -0,0 +1,354 @@
+/*
+ * 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.net;
+
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.NetlinkSocket;
+import android.net.netlink.RtNetlinkNeighborMessage;
+import android.net.netlink.StructNdaCacheInfo;
+import android.net.netlink.StructNdMsg;
+import android.net.netlink.StructNlMsgHdr;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.OsConstants;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * IpReachabilityMonitor.
+ *
+ * Monitors on-link IP reachability and notifies callers whenever any on-link
+ * addresses of interest appear to have become unresponsive.
+ *
+ * @hide
+ */
+public class IpReachabilityMonitor {
+ private static final String TAG = "IpReachabilityMonitor";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ public interface Callback {
+ public void notifyLost(InetAddress ip, String logMsg);
+ }
+
+ private final Object mLock = new Object();
+ private final String mInterfaceName;
+ private final int mInterfaceIndex;
+ private final Callback mCallback;
+ private final Set<InetAddress> mIpWatchList;
+ private int mIpWatchListVersion;
+ private boolean mRunning;
+ final private Thread mObserverThread;
+
+ // TODO: consider passing in a NetworkInterface object from the caller.
+ public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
+ mInterfaceName = ifName;
+ int ifIndex = -1;
+ try {
+ NetworkInterface netIf = NetworkInterface.getByName(ifName);
+ mInterfaceIndex = netIf.getIndex();
+ } catch (SocketException | NullPointerException e) {
+ throw new IllegalArgumentException("invalid interface '" + ifName + "': ", e);
+ }
+ mCallback = callback;
+ mIpWatchList = new HashSet<InetAddress>();
+ mIpWatchListVersion = 0;
+ mRunning = false;
+ mObserverThread = new Thread(new NetlinkSocketObserver());
+ mObserverThread.start();
+ }
+
+ public void stop() {
+ synchronized (mLock) {
+ mRunning = false;
+ mIpWatchList.clear();
+ }
+ }
+
+ // TODO: add a public dump() method that can be called during a bug report.
+
+ private static Set<InetAddress> getOnLinkNeighbors(LinkProperties lp) {
+ Set<InetAddress> allIps = new HashSet<InetAddress>();
+
+ final List<RouteInfo> routes = lp.getRoutes();
+ for (RouteInfo route : routes) {
+ if (route.hasGateway()) {
+ allIps.add(route.getGateway());
+ }
+ }
+
+ for (InetAddress nameserver : lp.getDnsServers()) {
+ allIps.add(nameserver);
+ }
+
+ try {
+ // Don't block here for DNS lookups. If the proxy happens to be an
+ // IP literal then we add it the list, but otherwise skip it.
+ allIps.add(NetworkUtils.numericToInetAddress(lp.getHttpProxy().getHost()));
+ } catch (NullPointerException|IllegalArgumentException e) {
+ // No proxy, PAC proxy, or proxy is not a literal IP address.
+ }
+
+ Set<InetAddress> neighbors = new HashSet<InetAddress>();
+ for (InetAddress ip : allIps) {
+ // TODO: consider using the prefixes of the LinkAddresses instead
+ // of the routes--it may be more accurate.
+ for (RouteInfo route : routes) {
+ if (route.hasGateway()) {
+ continue; // Not directly connected.
+ }
+ if (route.matches(ip)) {
+ neighbors.add(ip);
+ break;
+ }
+ }
+ }
+ return neighbors;
+ }
+
+ private String describeWatchList() {
+ synchronized (mLock) {
+ return "version{" + mIpWatchListVersion + "}, " +
+ "ips=[" + TextUtils.join(",", mIpWatchList) + "]";
+ }
+ }
+
+ private boolean isWatching(InetAddress ip) {
+ synchronized (mLock) {
+ return mRunning && mIpWatchList.contains(ip);
+ }
+ }
+
+ public void updateLinkProperties(LinkProperties lp) {
+ if (!mInterfaceName.equals(lp.getInterfaceName())) {
+ // TODO: figure out how to cope with interface changes.
+ Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() +
+ "' does not match: " + mInterfaceName);
+ return;
+ }
+
+ // We rely upon the caller to determine when LinkProperties have actually
+ // changed and call this at the appropriate time. Note that even though
+ // the LinkProperties may change, the set of on-link neighbors might not.
+ //
+ // Nevertheless, just clear and re-add everything.
+ final Set<InetAddress> neighbors = getOnLinkNeighbors(lp);
+ if (neighbors.isEmpty()) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mIpWatchList.clear();
+ mIpWatchList.addAll(neighbors);
+ mIpWatchListVersion++;
+ }
+ if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
+ }
+
+ public void clearLinkProperties() {
+ synchronized (mLock) {
+ mIpWatchList.clear();
+ mIpWatchListVersion++;
+ }
+ if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
+ }
+
+ private void notifyLost(InetAddress ip, String msg) {
+ if (!isWatching(ip)) {
+ // Ignore stray notifications. This can happen when, for example,
+ // several neighbors are reported unreachable or deleted
+ // back-to-back. Because these messages are parsed serially, and
+ // this method is called for each notification, the caller above us
+ // may have already processed an earlier lost notification and
+ // cleared the watch list as it moves to handle the situation.
+ return;
+ }
+ Log.w(TAG, "ALERT: " + ip.getHostAddress() + " -- " + msg);
+ if (mCallback != null) {
+ mCallback.notifyLost(ip, msg);
+ }
+ }
+
+
+ private final class NetlinkSocketObserver implements Runnable {
+ private static final String TAG = "NetlinkSocketObserver";
+ private NetlinkSocket mSocket;
+
+ @Override
+ public void run() {
+ if (VDBG) { Log.d(TAG, "Starting observing thread."); }
+ synchronized (mLock) { mRunning = true; }
+
+ try {
+ setupNetlinkSocket();
+ } catch (ErrnoException | SocketException e) {
+ Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
+ synchronized (mLock) { mRunning = false; }
+ }
+
+ ByteBuffer byteBuffer;
+ while (stillRunning()) {
+ try {
+ byteBuffer = recvKernelReply();
+ } catch (ErrnoException e) {
+ Log.w(TAG, "ErrnoException: ", e);
+ break;
+ }
+ final long whenMs = SystemClock.elapsedRealtime();
+ if (byteBuffer == null) {
+ continue;
+ }
+ parseNetlinkMessageBuffer(byteBuffer, whenMs);
+ }
+
+ clearNetlinkSocket();
+
+ synchronized (mLock) { mRunning = false; }
+ if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
+ }
+
+ private boolean stillRunning() {
+ synchronized (mLock) {
+ return mRunning;
+ }
+ }
+
+ private void clearNetlinkSocket() {
+ if (mSocket != null) {
+ mSocket.close();
+ }
+ mSocket = null;
+ }
+
+ // TODO: Refactor the main loop to recreate the socket upon recoverable errors.
+ private void setupNetlinkSocket() throws ErrnoException, SocketException {
+ clearNetlinkSocket();
+ mSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
+
+ final NetlinkSocketAddress listenAddr = new NetlinkSocketAddress(
+ 0, OsConstants.RTMGRP_NEIGH);
+ mSocket.bind(listenAddr);
+
+ if (VDBG) {
+ final NetlinkSocketAddress nlAddr = mSocket.getLocalAddress();
+ Log.d(TAG, "bound to sockaddr_nl{"
+ + ((long) (nlAddr.getPortId() & 0xffffffff)) + ", "
+ + nlAddr.getGroupsMask()
+ + "}");
+ }
+ }
+
+ private ByteBuffer recvKernelReply() throws ErrnoException {
+ try {
+ return mSocket.recvMessage(0);
+ } catch (InterruptedIOException e) {
+ // Interruption or other error, e.g. another thread closed our file descriptor.
+ } catch (ErrnoException e) {
+ if (e.errno != OsConstants.EAGAIN) {
+ throw e;
+ }
+ }
+ return null;
+ }
+
+ private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
+ while (byteBuffer.remaining() > 0) {
+ final int position = byteBuffer.position();
+ final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
+ if (nlMsg == null || nlMsg.getHeader() == null) {
+ byteBuffer.position(position);
+ Log.e(TAG, "unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
+ break;
+ }
+
+ final int srcPortId = nlMsg.getHeader().nlmsg_pid;
+ if (srcPortId != 0) {
+ Log.e(TAG, "non-kernel source portId: " + ((long) (srcPortId & 0xffffffff)));
+ break;
+ }
+
+ if (nlMsg instanceof NetlinkErrorMessage) {
+ Log.e(TAG, "netlink error: " + nlMsg);
+ continue;
+ } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
+ if (DBG) {
+ Log.d(TAG, "non-rtnetlink neighbor msg: " + nlMsg);
+ }
+ continue;
+ }
+
+ evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
+ }
+ }
+
+ private void evaluateRtNetlinkNeighborMessage(
+ RtNetlinkNeighborMessage neighMsg, long whenMs) {
+ final StructNdMsg ndMsg = neighMsg.getNdHeader();
+ if (ndMsg == null || ndMsg.ndm_ifindex != mInterfaceIndex) {
+ return;
+ }
+
+ final InetAddress destination = neighMsg.getDestination();
+ if (!isWatching(destination)) {
+ return;
+ }
+
+ final short msgType = neighMsg.getHeader().nlmsg_type;
+ final short nudState = ndMsg.ndm_state;
+ final String eventMsg = "NeighborEvent{"
+ + "elapsedMs=" + whenMs + ", "
+ + destination.getHostAddress() + ", "
+ + "[" + NetlinkConstants.hexify(neighMsg.getLinkLayerAddress()) + "], "
+ + NetlinkConstants.stringForNlMsgType(msgType) + ", "
+ + StructNdMsg.stringForNudState(nudState)
+ + "}";
+
+ if (VDBG) {
+ Log.d(TAG, neighMsg.toString());
+ } else if (DBG) {
+ Log.d(TAG, eventMsg);
+ }
+
+ if ((msgType == NetlinkConstants.RTM_DELNEIGH) ||
+ (nudState == StructNdMsg.NUD_FAILED)) {
+ final String logMsg = "FAILURE: " + eventMsg;
+ notifyLost(destination, logMsg);
+ }
+ }
+ }
+}
diff --git a/core/java/android/net/netlink/NetlinkConstants.java b/core/java/android/net/netlink/NetlinkConstants.java
new file mode 100644
index 0000000..e331701
--- /dev/null
+++ b/core/java/android/net/netlink/NetlinkConstants.java
@@ -0,0 +1,120 @@
+/*
+ * 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.net.netlink;
+
+import android.system.OsConstants;
+import com.android.internal.util.HexDump;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * Various constants and static helper methods for netlink communications.
+ *
+ * Values taken from:
+ *
+ * &lt;linux_src&gt;/include/uapi/linux/netlink.h
+ * &lt;linux_src&gt;/include/uapi/linux/rtnetlink.h
+ *
+ * @hide
+ */
+public class NetlinkConstants {
+ private NetlinkConstants() {}
+
+ public static final int NLA_ALIGNTO = 4;
+
+ public static final int alignedLengthOf(short length) {
+ final int intLength = (int) length & 0xffff;
+ return alignedLengthOf(intLength);
+ }
+
+ public static final int alignedLengthOf(int length) {
+ if (length <= 0) { return 0; }
+ return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
+ }
+
+ public static String stringForAddressFamily(int family) {
+ if (family == OsConstants.AF_INET) { return "AF_INET"; }
+ if (family == OsConstants.AF_INET6) { return "AF_INET6"; }
+ if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; }
+ return String.valueOf(family);
+ }
+
+ public static String hexify(byte[] bytes) {
+ if (bytes == null) { return "(null)"; }
+ return HexDump.toHexString(bytes);
+ }
+
+ public static String hexify(ByteBuffer buffer) {
+ if (buffer == null) { return "(null)"; }
+ return HexDump.toHexString(
+ buffer.array(), buffer.position(), buffer.remaining());
+ }
+
+ // Known values for struct nlmsghdr nlm_type.
+ public static final short NLMSG_NOOP = 1; // Nothing
+ public static final short NLMSG_ERROR = 2; // Error
+ public static final short NLMSG_DONE = 3; // End of a dump
+ public static final short NLMSG_OVERRUN = 4; // Data lost
+ public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value
+
+ public static final short RTM_NEWLINK = 16;
+ public static final short RTM_DELLINK = 17;
+ public static final short RTM_GETLINK = 18;
+ public static final short RTM_SETLINK = 19;
+ public static final short RTM_NEWADDR = 20;
+ public static final short RTM_DELADDR = 21;
+ public static final short RTM_GETADDR = 22;
+ public static final short RTM_NEWROUTE = 24;
+ public static final short RTM_DELROUTE = 25;
+ public static final short RTM_GETROUTE = 26;
+ public static final short RTM_NEWNEIGH = 28;
+ public static final short RTM_DELNEIGH = 29;
+ public static final short RTM_GETNEIGH = 30;
+ public static final short RTM_NEWRULE = 32;
+ public static final short RTM_DELRULE = 33;
+ public static final short RTM_GETRULE = 34;
+ public static final short RTM_NEWNDUSEROPT = 68;
+
+ public static String stringForNlMsgType(short nlm_type) {
+ switch (nlm_type) {
+ case NLMSG_NOOP: return "NLMSG_NOOP";
+ case NLMSG_ERROR: return "NLMSG_ERROR";
+ case NLMSG_DONE: return "NLMSG_DONE";
+ case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
+ case RTM_NEWLINK: return "RTM_NEWLINK";
+ case RTM_DELLINK: return "RTM_DELLINK";
+ case RTM_GETLINK: return "RTM_GETLINK";
+ case RTM_SETLINK: return "RTM_SETLINK";
+ case RTM_NEWADDR: return "RTM_NEWADDR";
+ case RTM_DELADDR: return "RTM_DELADDR";
+ case RTM_GETADDR: return "RTM_GETADDR";
+ case RTM_NEWROUTE: return "RTM_NEWROUTE";
+ case RTM_DELROUTE: return "RTM_DELROUTE";
+ case RTM_GETROUTE: return "RTM_GETROUTE";
+ case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
+ case RTM_DELNEIGH: return "RTM_DELNEIGH";
+ case RTM_GETNEIGH: return "RTM_GETNEIGH";
+ case RTM_NEWRULE: return "RTM_NEWRULE";
+ case RTM_DELRULE: return "RTM_DELRULE";
+ case RTM_GETRULE: return "RTM_GETRULE";
+ case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
+ default:
+ return "unknown RTM type: " + String.valueOf(nlm_type);
+ }
+ }
+}
diff --git a/core/java/android/net/netlink/NetlinkErrorMessage.java b/core/java/android/net/netlink/NetlinkErrorMessage.java
new file mode 100644
index 0000000..dbc10d6
--- /dev/null
+++ b/core/java/android/net/netlink/NetlinkErrorMessage.java
@@ -0,0 +1,62 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.StructNlMsgHdr;
+import android.net.netlink.NetlinkMessage;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * A NetlinkMessage subclass for netlink error messages.
+ *
+ * @hide
+ */
+public class NetlinkErrorMessage extends NetlinkMessage {
+
+ public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
+ final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header);
+
+ errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer);
+ if (errorMsg.mNlMsgErr == null) {
+ return null;
+ }
+
+ return errorMsg;
+ }
+
+ private StructNlMsgErr mNlMsgErr;
+
+ NetlinkErrorMessage(StructNlMsgHdr header) {
+ super(header);
+ mNlMsgErr = null;
+ }
+
+ public StructNlMsgErr getNlMsgError() {
+ return mNlMsgErr;
+ }
+
+ @Override
+ public String toString() {
+ return "NetlinkErrorMessage{ "
+ + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
+ + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} "
+ + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/NetlinkMessage.java b/core/java/android/net/netlink/NetlinkMessage.java
new file mode 100644
index 0000000..bc04a16
--- /dev/null
+++ b/core/java/android/net/netlink/NetlinkMessage.java
@@ -0,0 +1,97 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.RtNetlinkNeighborMessage;
+import android.net.netlink.StructNlAttr;
+import android.net.netlink.StructNlMsgHdr;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * NetlinkMessage base class for other, more specific netlink message types.
+ *
+ * Classes that extend NetlinkMessage should:
+ * - implement a public static parse(StructNlMsgHdr, ByteBuffer) method
+ * - returning either null (parse errors) or a new object of the subclass
+ * type (cast-able to NetlinkMessage)
+ *
+ * NetlinkMessage.parse() should be updated to know which nlmsg_type values
+ * correspond with which message subclasses.
+ *
+ * @hide
+ */
+public class NetlinkMessage {
+ private final static String TAG = "NetlinkMessage";
+
+ public static NetlinkMessage parse(ByteBuffer byteBuffer) {
+ final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
+ final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
+ if (nlmsghdr == null) {
+ return null;
+ }
+
+ int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
+ payloadLength -= StructNlMsgHdr.STRUCT_SIZE;
+ if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) {
+ // Malformed message or runt buffer. Pretend the buffer was consumed.
+ byteBuffer.position(byteBuffer.limit());
+ return null;
+ }
+
+ switch (nlmsghdr.nlmsg_type) {
+ //case NetlinkConstants.NLMSG_NOOP:
+ case NetlinkConstants.NLMSG_ERROR:
+ return (NetlinkMessage) NetlinkErrorMessage.parse(byteBuffer);
+ case NetlinkConstants.NLMSG_DONE:
+ byteBuffer.position(byteBuffer.position() + payloadLength);
+ return new NetlinkMessage(nlmsghdr);
+ //case NetlinkConstants.NLMSG_OVERRUN:
+ case NetlinkConstants.RTM_NEWNEIGH:
+ case NetlinkConstants.RTM_DELNEIGH:
+ case NetlinkConstants.RTM_GETNEIGH:
+ return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
+ default:
+ if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
+ // Netlink control message. Just parse the header for now,
+ // pretending the whole message was consumed.
+ byteBuffer.position(byteBuffer.position() + payloadLength);
+ return new NetlinkMessage(nlmsghdr);
+ }
+ return null;
+ }
+ }
+
+ protected StructNlMsgHdr mHeader;
+
+ public NetlinkMessage(StructNlMsgHdr nlmsghdr) {
+ mHeader = nlmsghdr;
+ }
+
+ public StructNlMsgHdr getHeader() {
+ return mHeader;
+ }
+
+ @Override
+ public String toString() {
+ return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/NetlinkSocket.java b/core/java/android/net/netlink/NetlinkSocket.java
new file mode 100644
index 0000000..657d48c
--- /dev/null
+++ b/core/java/android/net/netlink/NetlinkSocket.java
@@ -0,0 +1,169 @@
+/*
+ * 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.net.netlink;
+
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructTimeval;
+import android.util.Log;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+
+/**
+ * NetlinkSocket
+ *
+ * A small wrapper class to assist with AF_NETLINK socket operations.
+ *
+ * @hide
+ */
+public class NetlinkSocket implements Closeable {
+ private static final String TAG = "NetlinkSocket";
+ private static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
+ private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
+
+ final private FileDescriptor mDescriptor;
+ private NetlinkSocketAddress mAddr;
+ private long mLastRecvTimeoutMs;
+ private long mLastSendTimeoutMs;
+
+ public NetlinkSocket(int nlProto) throws ErrnoException {
+ mDescriptor = Os.socket(
+ OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto);
+
+ Libcore.os.setsockoptInt(
+ mDescriptor, OsConstants.SOL_SOCKET,
+ OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ }
+
+ public NetlinkSocketAddress getLocalAddress() throws ErrnoException {
+ return (NetlinkSocketAddress) Os.getsockname(mDescriptor);
+ }
+
+ public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException {
+ Os.bind(mDescriptor, (SocketAddress)localAddr);
+ }
+
+ public void connectTo(NetlinkSocketAddress peerAddr)
+ throws ErrnoException, SocketException {
+ Os.connect(mDescriptor, (SocketAddress) peerAddr);
+ }
+
+ public void connectToKernel() throws ErrnoException, SocketException {
+ connectTo(new NetlinkSocketAddress(0, 0));
+ }
+
+ /**
+ * Wait indefinitely (or until underlying socket error) for a
+ * netlink message of at most DEFAULT_RECV_BUFSIZE size.
+ */
+ public ByteBuffer recvMessage()
+ throws ErrnoException, InterruptedIOException {
+ return recvMessage(DEFAULT_RECV_BUFSIZE, 0);
+ }
+
+ /**
+ * Wait up to |timeoutMs| (or until underlying socket error) for a
+ * netlink message of at most DEFAULT_RECV_BUFSIZE size.
+ */
+ public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException {
+ return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs);
+ }
+
+ private void checkTimeout(long timeoutMs) {
+ if (timeoutMs < 0) {
+ throw new IllegalArgumentException("Negative timeouts not permitted");
+ }
+ }
+
+ /**
+ * Wait up to |timeoutMs| (or until underlying socket error) for a
+ * netlink message of at most |bufsize| size.
+ *
+ * Multi-threaded calls with different timeouts will cause unexpected results.
+ */
+ public ByteBuffer recvMessage(int bufsize, long timeoutMs)
+ throws ErrnoException, IllegalArgumentException, InterruptedIOException {
+ checkTimeout(timeoutMs);
+
+ synchronized (mDescriptor) {
+ if (mLastRecvTimeoutMs != timeoutMs) {
+ Os.setsockoptTimeval(mDescriptor,
+ OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
+ StructTimeval.fromMillis(timeoutMs));
+ mLastRecvTimeoutMs = timeoutMs;
+ }
+ }
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
+ int length = Os.read(mDescriptor, byteBuffer);
+ if (length == bufsize) {
+ Log.w(TAG, "maximum read");
+ }
+ byteBuffer.position(0);
+ byteBuffer.limit(length);
+ byteBuffer.order(ByteOrder.nativeOrder());
+ return byteBuffer;
+ }
+
+ /**
+ * Send a message to a peer to which this socket has previously connected.
+ *
+ * This blocks until completion or an error occurs.
+ */
+ public boolean sendMessage(byte[] bytes, int offset, int count)
+ throws ErrnoException, InterruptedIOException {
+ return sendMessage(bytes, offset, count, 0);
+ }
+
+ /**
+ * Send a message to a peer to which this socket has previously connected,
+ * waiting at most |timeoutMs| milliseconds for the send to complete.
+ *
+ * Multi-threaded calls with different timeouts will cause unexpected results.
+ */
+ public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs)
+ throws ErrnoException, IllegalArgumentException, InterruptedIOException {
+ checkTimeout(timeoutMs);
+
+ synchronized (mDescriptor) {
+ if (mLastSendTimeoutMs != timeoutMs) {
+ Os.setsockoptTimeval(mDescriptor,
+ OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
+ StructTimeval.fromMillis(timeoutMs));
+ mLastSendTimeoutMs = timeoutMs;
+ }
+ }
+
+ return (count == Os.write(mDescriptor, bytes, offset, count));
+ }
+
+ @Override
+ public void close() {
+ IoUtils.closeQuietly(mDescriptor);
+ }
+}
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
new file mode 100644
index 0000000..d4b572c
--- /dev/null
+++ b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
@@ -0,0 +1,181 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.StructNdaCacheInfo;
+import android.net.netlink.StructNdMsg;
+import android.net.netlink.StructNlAttr;
+import android.net.netlink.StructNlMsgHdr;
+import android.net.netlink.NetlinkMessage;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+
+/**
+ * A NetlinkMessage subclass for netlink error messages.
+ *
+ * see also: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
+ *
+ * @hide
+ */
+public class RtNetlinkNeighborMessage extends NetlinkMessage {
+ public static final short NDA_UNSPEC = 0;
+ public static final short NDA_DST = 1;
+ public static final short NDA_LLADDR = 2;
+ public static final short NDA_CACHEINFO = 3;
+ public static final short NDA_PROBES = 4;
+ public static final short NDA_VLAN = 5;
+ public static final short NDA_PORT = 6;
+ public static final short NDA_VNI = 7;
+ public static final short NDA_IFINDEX = 8;
+ public static final short NDA_MASTER = 9;
+
+ private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) {
+ while (byteBuffer != null && byteBuffer.remaining() > 0) {
+ final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
+ if (nlAttr == null) {
+ break;
+ }
+ if (nlAttr.nla_type == attrType) {
+ return StructNlAttr.parse(byteBuffer);
+ }
+ if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
+ break;
+ }
+ byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
+ }
+ return null;
+ }
+
+ public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
+ final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
+
+ neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
+ if (neighMsg.mNdmsg == null) {
+ return null;
+ }
+
+ // Some of these are message-type dependent, and not always present.
+ final int baseOffset = byteBuffer.position();
+ StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer);
+ if (nlAttr != null) {
+ neighMsg.mDestination = nlAttr.getValueAsInetAddress();
+ }
+
+ byteBuffer.position(baseOffset);
+ nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer);
+ if (nlAttr != null) {
+ neighMsg.mLinkLayerAddr = nlAttr.nla_value;
+ }
+
+ byteBuffer.position(baseOffset);
+ nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer);
+ if (nlAttr != null) {
+ neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
+ }
+
+ byteBuffer.position(baseOffset);
+ nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
+ if (nlAttr != null) {
+ neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
+ }
+
+ final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
+ final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
+ neighMsg.mHeader.nlmsg_len - kMinConsumed);
+ if (byteBuffer.remaining() < kAdditionalSpace) {
+ byteBuffer.position(byteBuffer.limit());
+ } else {
+ byteBuffer.position(baseOffset + kAdditionalSpace);
+ }
+
+ return neighMsg;
+ }
+
+ /**
+ * A convenience method to create an RTM_GETNEIGH request message.
+ */
+ public static byte[] newGetNeighborsRequest(int seqNo) {
+ final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
+ final byte[] bytes = new byte[length];
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+ nlmsghdr.nlmsg_len = length;
+ nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
+ nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST|StructNlMsgHdr.NLM_F_DUMP;
+ nlmsghdr.nlmsg_seq = seqNo;
+ nlmsghdr.pack(byteBuffer);
+
+ final StructNdMsg ndmsg = new StructNdMsg();
+ ndmsg.pack(byteBuffer);
+
+ return bytes;
+ }
+
+ private StructNdMsg mNdmsg;
+ private InetAddress mDestination;
+ private byte[] mLinkLayerAddr;
+ private int mNumProbes;
+ private StructNdaCacheInfo mCacheInfo;
+
+ private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
+ super(header);
+ mNdmsg = null;
+ mDestination = null;
+ mLinkLayerAddr = null;
+ mNumProbes = 0;
+ mCacheInfo = null;
+ }
+
+ public StructNdMsg getNdHeader() {
+ return mNdmsg;
+ }
+
+ public InetAddress getDestination() {
+ return mDestination;
+ }
+
+ public byte[] getLinkLayerAddress() {
+ return mLinkLayerAddr;
+ }
+
+ public int getProbes() {
+ return mNumProbes;
+ }
+
+ public StructNdaCacheInfo getCacheInfo() {
+ return mCacheInfo;
+ }
+
+ @Override
+ public String toString() {
+ final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
+ return "RtNetlinkNeighborMessage{ "
+ + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
+ + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
+ + "destination{" + ipLiteral + "} "
+ + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
+ + "probes{" + mNumProbes + "} "
+ + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
+ + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/StructNdMsg.java b/core/java/android/net/netlink/StructNdMsg.java
new file mode 100644
index 0000000..e66d45d
--- /dev/null
+++ b/core/java/android/net/netlink/StructNdMsg.java
@@ -0,0 +1,162 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.NetlinkConstants;
+import android.system.OsConstants;
+import java.nio.ByteBuffer;
+
+
+/**
+ * struct ndmsg
+ *
+ * see: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
+ *
+ * @hide
+ */
+public class StructNdMsg {
+ // Already aligned.
+ public static final int STRUCT_SIZE = 12;
+
+ // Neighbor Cache Entry States
+ public static final short NUD_INCOMPLETE = 0x01;
+ public static final short NUD_REACHABLE = 0x02;
+ public static final short NUD_STALE = 0x04;
+ public static final short NUD_DELAY = 0x08;
+ public static final short NUD_PROBE = 0x10;
+ public static final short NUD_FAILED = 0x20;
+ public static final short NUD_NOARP = 0x40;
+ public static final short NUD_PERMANENT = 0x80;
+
+ public static String stringForNudState(short nudState) {
+ switch (nudState) {
+ case NUD_INCOMPLETE: return "NUD_INCOMPLETE";
+ case NUD_REACHABLE: return "NUD_REACHABLE";
+ case NUD_STALE: return "NUD_STALE";
+ case NUD_DELAY: return "NUD_DELAY";
+ case NUD_PROBE: return "NUD_PROBE";
+ case NUD_FAILED: return "NUD_FAILED";
+ case NUD_NOARP: return "NUD_NOARP";
+ case NUD_PERMANENT: return "NUD_PERMANENT";
+ default:
+ return "unknown NUD state: " + String.valueOf(nudState);
+ }
+ }
+
+ public static boolean isNudStateConnected(short nudState) {
+ return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
+ }
+
+ // Neighbor Cache Entry Flags
+ public static byte NTF_USE = (byte) 0x01;
+ public static byte NTF_SELF = (byte) 0x02;
+ public static byte NTF_MASTER = (byte) 0x04;
+ public static byte NTF_PROXY = (byte) 0x08;
+ public static byte NTF_ROUTER = (byte) 0x80;
+
+ public static String stringForNudFlags(byte flags) {
+ final StringBuilder sb = new StringBuilder();
+ if ((flags & NTF_USE) != 0) {
+ sb.append("NTF_USE");
+ }
+ if ((flags & NTF_SELF) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NTF_SELF");
+ }
+ if ((flags & NTF_MASTER) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NTF_MASTER");
+ }
+ if ((flags & NTF_PROXY) != 0) {
+ if (sb.length() > 0) { sb.append("|");
+ }
+ sb.append("NTF_PROXY"); }
+ if ((flags & NTF_ROUTER) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NTF_ROUTER");
+ }
+ return sb.toString();
+ }
+
+ private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
+ return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
+ }
+
+ public static StructNdMsg parse(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return null; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the possible
+ // exception of usage within unittests.
+ final StructNdMsg struct = new StructNdMsg();
+ struct.ndm_family = byteBuffer.get();
+ final byte pad1 = byteBuffer.get();
+ final short pad2 = byteBuffer.getShort();
+ struct.ndm_ifindex = byteBuffer.getInt();
+ struct.ndm_state = byteBuffer.getShort();
+ struct.ndm_flags = byteBuffer.get();
+ struct.ndm_type = byteBuffer.get();
+ return struct;
+ }
+
+ public byte ndm_family;
+ public int ndm_ifindex;
+ public short ndm_state;
+ public byte ndm_flags;
+ public byte ndm_type;
+
+ public StructNdMsg() {
+ ndm_family = (byte) OsConstants.AF_UNSPEC;
+ }
+
+ public boolean pack(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return false; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the exception
+ // of usage within unittests.
+ byteBuffer.put(ndm_family);
+ byteBuffer.put((byte) 0); // pad1
+ byteBuffer.putShort((short) 0); // pad2
+ byteBuffer.putInt(ndm_ifindex);
+ byteBuffer.putShort(ndm_state);
+ byteBuffer.put(ndm_flags);
+ byteBuffer.put(ndm_type);
+ return true;
+ }
+
+ public boolean nudConnected() {
+ return isNudStateConnected(ndm_state);
+ }
+
+ public boolean nudValid() {
+ return (nudConnected() || ((ndm_state & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ }
+
+ @Override
+ public String toString() {
+ final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")";
+ final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")";
+ return "StructNdMsg{ "
+ + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, "
+ + "ifindex{" + ndm_ifindex + "}, "
+ + "state{" + stateStr + "}, "
+ + "flags{" + flagsStr + "}, "
+ + "type{" + ndm_type + "} "
+ + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/StructNdaCacheInfo.java b/core/java/android/net/netlink/StructNdaCacheInfo.java
new file mode 100644
index 0000000..16cf563
--- /dev/null
+++ b/core/java/android/net/netlink/StructNdaCacheInfo.java
@@ -0,0 +1,117 @@
+/*
+ * 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.net.netlink;
+
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * struct nda_cacheinfo
+ *
+ * see: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
+ *
+ * @hide
+ */
+public class StructNdaCacheInfo {
+ // Already aligned.
+ public static final int STRUCT_SIZE = 16;
+
+ private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
+ return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
+ }
+
+ public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return null; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the possible
+ // exception of usage within unittests.
+ final StructNdaCacheInfo struct = new StructNdaCacheInfo();
+ struct.ndm_used = byteBuffer.getInt();
+ struct.ndm_confirmed = byteBuffer.getInt();
+ struct.ndm_updated = byteBuffer.getInt();
+ struct.ndm_refcnt = byteBuffer.getInt();
+ return struct;
+ }
+
+ // TODO: investigate whether this can change during device runtime and
+ // decide what (if anything) should be done about that.
+ private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);
+
+ private static long ticksToMilliSeconds(int intClockTicks) {
+ final long longClockTicks = (long) intClockTicks & 0xffffffff;
+ return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
+ }
+
+ /**
+ * Explanatory notes, for reference.
+ *
+ * Before being returned to user space, the neighbor entry times are
+ * converted to clock_t's like so:
+ *
+ * ndm_used = jiffies_to_clock_t(now - neigh->used);
+ * ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
+ * ndm_updated = jiffies_to_clock_t(now - neigh->updated);
+ *
+ * meaning that these values are expressed as "clock ticks ago". To
+ * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
+ * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
+ * in centiseconds.
+ *
+ * These values are unsigned, but fortunately being expressed as "some
+ * clock ticks ago", these values are typically very small (and
+ * 2^31 centiseconds = 248 days).
+ *
+ * By observation, it appears that:
+ * ndm_used: the last time ARP/ND took place for this neighbor
+ * ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR
+ * higher layer confirmation (TCP or MSG_CONFIRM)
+ * was received
+ * ndm_updated: the time when the current NUD state was entered
+ */
+ public int ndm_used;
+ public int ndm_confirmed;
+ public int ndm_updated;
+ public int ndm_refcnt;
+
+ public StructNdaCacheInfo() {}
+
+ public long lastUsed() {
+ return ticksToMilliSeconds(ndm_used);
+ }
+
+ public long lastConfirmed() {
+ return ticksToMilliSeconds(ndm_confirmed);
+ }
+
+ public long lastUpdated() {
+ return ticksToMilliSeconds(ndm_updated);
+ }
+
+ @Override
+ public String toString() {
+ return "NdaCacheInfo{ "
+ + "ndm_used{" + lastUsed() + "}, "
+ + "ndm_confirmed{" + lastConfirmed() + "}, "
+ + "ndm_updated{" + lastUpdated() + "}, "
+ + "ndm_refcnt{" + ndm_refcnt + "} "
+ + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/StructNlAttr.java b/core/java/android/net/netlink/StructNlAttr.java
new file mode 100644
index 0000000..9aef4c7
--- /dev/null
+++ b/core/java/android/net/netlink/StructNlAttr.java
@@ -0,0 +1,127 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.NetlinkConstants;
+import libcore.io.SizeOf;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+
+/**
+ * struct nlattr
+ *
+ * see: &lt;linux_src&gt;/include/uapi/linux/netlink.h
+ *
+ * @hide
+ */
+public class StructNlAttr {
+ // Already aligned.
+ public static final int NLA_HEADERLEN = 4;
+
+ // Return a (length, type) object only, without consuming any bytes in
+ // |byteBuffer| and without copying or interpreting any value bytes.
+ // This is used for scanning over a packed set of struct nlattr's,
+ // looking for instances of a particular type.
+ public static StructNlAttr peek(ByteBuffer byteBuffer) {
+ if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
+ return null;
+ }
+ final int baseOffset = byteBuffer.position();
+
+ final StructNlAttr struct = new StructNlAttr();
+ struct.nla_len = byteBuffer.getShort();
+ struct.nla_type = byteBuffer.getShort();
+ struct.mByteOrder = byteBuffer.order();
+
+ byteBuffer.position(baseOffset);
+ if (struct.nla_len < NLA_HEADERLEN) {
+ // Malformed.
+ return null;
+ }
+ return struct;
+ }
+
+ public static StructNlAttr parse(ByteBuffer byteBuffer) {
+ final StructNlAttr struct = peek(byteBuffer);
+ if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
+ return null;
+ }
+
+ final int baseOffset = byteBuffer.position();
+ byteBuffer.position(baseOffset + NLA_HEADERLEN);
+
+ int valueLen = ((int) struct.nla_len) & 0xffff;
+ valueLen -= NLA_HEADERLEN;
+ if (valueLen > 0) {
+ struct.nla_value = new byte[valueLen];
+ byteBuffer.get(struct.nla_value, 0, valueLen);
+ byteBuffer.position(baseOffset + struct.getAlignedLength());
+ }
+ return struct;
+ }
+
+ public short nla_len;
+ public short nla_type;
+ public byte[] nla_value;
+ public ByteOrder mByteOrder;
+
+ public StructNlAttr() {
+ mByteOrder = ByteOrder.nativeOrder();
+ }
+
+ public int getAlignedLength() {
+ return NetlinkConstants.alignedLengthOf(nla_len);
+ }
+
+ public ByteBuffer getValueAsByteBuffer() {
+ if (nla_value == null) { return null; }
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
+ byteBuffer.order(mByteOrder);
+ return byteBuffer;
+ }
+
+ public int getValueAsInt(int defaultValue) {
+ final ByteBuffer byteBuffer = getValueAsByteBuffer();
+ if (byteBuffer == null || byteBuffer.remaining() != SizeOf.INT) {
+ return defaultValue;
+ }
+ return getValueAsByteBuffer().getInt();
+ }
+
+ public InetAddress getValueAsInetAddress() {
+ if (nla_value == null) { return null; }
+
+ try {
+ return InetAddress.getByAddress(nla_value);
+ } catch (UnknownHostException ignored) {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "StructNlAttr{ "
+ + "nla_len{" + nla_len + "}, "
+ + "nla_type{" + nla_type + "}, "
+ + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
+ + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/core/java/android/net/netlink/StructNlMsgErr.java
new file mode 100644
index 0000000..5da19a2
--- /dev/null
+++ b/core/java/android/net/netlink/StructNlMsgErr.java
@@ -0,0 +1,80 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.StructNlMsgHdr;
+import libcore.io.SizeOf;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * struct nlmsgerr
+ *
+ * see &lt;linux_src&gt;/include/uapi/linux/netlink.h
+ *
+ * @hide
+ */
+public class StructNlMsgErr {
+ public static final int STRUCT_SIZE = SizeOf.INT + StructNlMsgHdr.STRUCT_SIZE;
+
+ public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
+ return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
+ }
+
+ public static StructNlMsgErr parse(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return null; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the exception
+ // of usage within unittests.
+ final StructNlMsgErr struct = new StructNlMsgErr();
+ struct.error = byteBuffer.getInt();
+ struct.msg = StructNlMsgHdr.parse(byteBuffer);
+ return struct;
+ }
+
+ public int error;
+ public StructNlMsgHdr msg;
+
+ public StructNlMsgErr() {
+ error = 0;
+ msg = null;
+ }
+
+ public boolean pack(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return false; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the possible
+ // exception of usage within unittests.
+ byteBuffer.putInt(error);
+ if (msg != null) {
+ msg.pack(byteBuffer);
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "StructNlMsgErr{ "
+ + "error{" + error + "}, "
+ + "msg{" + (msg == null ? "" : msg.toString()) + "} "
+ + "}";
+ }
+}
diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/core/java/android/net/netlink/StructNlMsgHdr.java
new file mode 100644
index 0000000..67925ac
--- /dev/null
+++ b/core/java/android/net/netlink/StructNlMsgHdr.java
@@ -0,0 +1,137 @@
+/*
+ * 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.net.netlink;
+
+import android.net.netlink.NetlinkConstants;
+import java.nio.ByteBuffer;
+
+
+/**
+ * struct nlmsghdr
+ *
+ * see &lt;linux_src&gt;/include/uapi/linux/netlink.h
+ *
+ * @hide
+ */
+public class StructNlMsgHdr {
+ // Already aligned.
+ public static final int STRUCT_SIZE = 16;
+
+ public static final short NLM_F_REQUEST = 0x0001;
+ public static final short NLM_F_MULTI = 0x0002;
+ public static final short NLM_F_ACK = 0x0004;
+ public static final short NLM_F_ECHO = 0x0008;
+ // Flags for a GET request.
+ public static final short NLM_F_ROOT = 0x0100;
+ public static final short NLM_F_MATCH = 0x0200;
+ public static final short NLM_F_DUMP = NLM_F_ROOT|NLM_F_MATCH;
+
+ public static String stringForNlMsgFlags(short flags) {
+ final StringBuilder sb = new StringBuilder();
+ if ((flags & NLM_F_REQUEST) != 0) {
+ sb.append("NLM_F_REQUEST");
+ }
+ if ((flags & NLM_F_MULTI) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NLM_F_MULTI");
+ }
+ if ((flags & NLM_F_ACK) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NLM_F_ACK");
+ }
+ if ((flags & NLM_F_ECHO) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NLM_F_ECHO");
+ }
+ if ((flags & NLM_F_ROOT) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NLM_F_ROOT");
+ }
+ if ((flags & NLM_F_MATCH) != 0) {
+ if (sb.length() > 0) { sb.append("|"); }
+ sb.append("NLM_F_MATCH");
+ }
+ return sb.toString();
+ }
+
+ public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
+ return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
+ }
+
+ public static StructNlMsgHdr parse(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return null; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the exception
+ // of usage within unittests.
+ final StructNlMsgHdr struct = new StructNlMsgHdr();
+ struct.nlmsg_len = byteBuffer.getInt();
+ struct.nlmsg_type = byteBuffer.getShort();
+ struct.nlmsg_flags = byteBuffer.getShort();
+ struct.nlmsg_seq = byteBuffer.getInt();
+ struct.nlmsg_pid = byteBuffer.getInt();
+
+ if (struct.nlmsg_len < STRUCT_SIZE) {
+ // Malformed.
+ return null;
+ }
+ return struct;
+ }
+
+ public int nlmsg_len;
+ public short nlmsg_type;
+ public short nlmsg_flags;
+ public int nlmsg_seq;
+ public int nlmsg_pid;
+
+ public StructNlMsgHdr() {
+ nlmsg_len = 0;
+ nlmsg_type = 0;
+ nlmsg_flags = 0;
+ nlmsg_seq = 0;
+ nlmsg_pid = 0;
+ }
+
+ public boolean pack(ByteBuffer byteBuffer) {
+ if (!hasAvailableSpace(byteBuffer)) { return false; }
+
+ // The ByteOrder must have already been set by the caller. In most
+ // cases ByteOrder.nativeOrder() is correct, with the possible
+ // exception of usage within unittests.
+ byteBuffer.putInt(nlmsg_len);
+ byteBuffer.putShort(nlmsg_type);
+ byteBuffer.putShort(nlmsg_flags);
+ byteBuffer.putInt(nlmsg_seq);
+ byteBuffer.putInt(nlmsg_pid);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final String typeStr = "" + nlmsg_type
+ + "(" + NetlinkConstants.stringForNlMsgType(nlmsg_type) + ")";
+ final String flagsStr = "" + nlmsg_flags
+ + "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
+ return "StructNlMsgHdr{ "
+ + "nlmsg_len{" + nlmsg_len + "}, "
+ + "nlmsg_type{" + typeStr + "}, "
+ + "nlmsg_flags{" + flagsStr + ")}, "
+ + "nlmsg_seq{" + nlmsg_seq + "}, "
+ + "nlmsg_pid{" + nlmsg_pid + "} "
+ + "}";
+ }
+}
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 3cb29ff..602bfea 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -23,4 +23,5 @@ interface IDeviceIdleController {
String[] getSystemPowerWhitelist();
String[] getFullPowerWhitelist();
int[] getAppIdWhitelist();
+ boolean isPowerSaveWhitelistApp(String name);
}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 00ab262..9a0d0d0 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -134,4 +134,6 @@ public abstract class PowerManagerInternal {
}
public abstract void setDeviceIdleMode(boolean enabled);
+
+ public abstract void setDeviceIdleWhitelist(int[] appids);
}
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index fcde3f4..2b058a8 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1099,6 +1099,20 @@ public interface IMountService extends IInterface {
}
@Override
+ public void forgetAllVolumes() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_forgetAllVolumes, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
public String getPrimaryStorageUuid() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1238,9 +1252,10 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 53;
static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 54;
static final int TRANSACTION_forgetVolume = IBinder.FIRST_CALL_TRANSACTION + 55;
+ static final int TRANSACTION_forgetAllVolumes = IBinder.FIRST_CALL_TRANSACTION + 56;
- static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 56;
- static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 57;
+ static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 57;
+ static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 58;
/**
* Cast an IBinder object into an IMountService interface, generating a
@@ -1757,6 +1772,12 @@ public interface IMountService extends IInterface {
reply.writeNoException();
return true;
}
+ case TRANSACTION_forgetAllVolumes: {
+ data.enforceInterface(DESCRIPTOR);
+ forgetAllVolumes();
+ reply.writeNoException();
+ return true;
+ }
case TRANSACTION_getPrimaryStorageUuid: {
data.enforceInterface(DESCRIPTOR);
String volumeUuid = getPrimaryStorageUuid();
@@ -2075,6 +2096,7 @@ public interface IMountService extends IInterface {
public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException;
public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException;
public void forgetVolume(String fsUuid) throws RemoteException;
+ public void forgetAllVolumes() throws RemoteException;
public String getPrimaryStorageUuid() throws RemoteException;
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dc70d7b..d3a5561 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5517,6 +5517,12 @@ public final class Settings {
public static final String APP_IDLE_DURATION = "app_idle_duration";
/**
+ * Controls whether double tap to wake is enabled.
+ * @hide
+ */
+ public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -5571,7 +5577,8 @@ public final class Settings {
MOUNT_UMS_PROMPT,
MOUNT_UMS_NOTIFY_ENABLED,
UI_NIGHT_MODE,
- SLEEP_TIMEOUT
+ SLEEP_TIMEOUT,
+ DOUBLE_TAP_TO_WAKE,
};
/**
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
index f0ca276..50c435a 100644
--- a/core/java/android/service/chooser/ChooserTarget.java
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,6 +35,16 @@ import android.util.Log;
/**
* A ChooserTarget represents a deep-link into an application as returned by a
* {@link android.service.chooser.ChooserTargetService}.
+ *
+ * <p>A chooser target represents a specific deep link target into an application exposed
+ * for selection by the user. This might be a frequently emailed contact, a recently active
+ * group messaging conversation, a folder in a cloud storage app, a collection of related
+ * items published on a social media service or any other contextually relevant grouping
+ * of target app + relevant metadata.</p>
+ *
+ * <p>Creators of chooser targets should consult the relevant design guidelines for the type
+ * of target they are presenting. For example, targets involving people should be presented
+ * with a circular icon.</p>
*/
public final class ChooserTarget implements Parcelable {
private static final String TAG = "ChooserTarget";
@@ -48,7 +59,7 @@ public final class ChooserTarget implements Parcelable {
* The icon that will be shown to the user to represent this target.
* The system may resize this icon as appropriate.
*/
- private Bitmap mIcon;
+ private Icon mIcon;
/**
* The IntentSender that will be used to deliver the intent to the target.
@@ -58,12 +69,6 @@ public final class ChooserTarget implements Parcelable {
private IntentSender mIntentSender;
/**
- * A raw intent provided in lieu of an IntentSender. Will be filled in and sent
- * by {@link #sendIntent(Context, Intent)}.
- */
- private Intent mIntent;
-
- /**
* The score given to this item. It can be normalized.
*/
private float mScore;
@@ -99,7 +104,7 @@ public final class ChooserTarget implements Parcelable {
* @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,
+ public ChooserTarget(CharSequence title, Icon icon, float score,
PendingIntent pendingIntent) {
this(title, icon, score, pendingIntent.getIntentSender());
}
@@ -135,7 +140,7 @@ public final class ChooserTarget implements Parcelable {
* @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) {
+ public ChooserTarget(CharSequence title, Icon icon, float score, IntentSender intentSender) {
mTitle = title;
mIcon = icon;
if (score > 1.f || score < 0.f) {
@@ -146,55 +151,15 @@ public final class ChooserTarget implements Parcelable {
mIntentSender = intentSender;
}
- /**
- * 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).
- * Scores for a set of targets do not need to sum to 1.</p>
- *
- * <p>Before being sent, the Intent supplied will be
- * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
- * to the chooser.</p>
- *
- * <p>Take care not to place custom {@link android.os.Parcelable} types into
- * the Intent 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 intent Intent to fill in and send if the user chooses this target
- */
- public ChooserTarget(CharSequence title, Bitmap icon, float score, Intent intent) {
- 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;
- mIntent = intent;
- }
-
ChooserTarget(Parcel in) {
mTitle = in.readCharSequence();
if (in.readInt() != 0) {
- mIcon = Bitmap.CREATOR.createFromParcel(in);
+ mIcon = Icon.CREATOR.createFromParcel(in);
} else {
mIcon = null;
}
mScore = in.readFloat();
mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
- if (in.readInt() != 0) {
- mIntent = Intent.CREATOR.createFromParcel(in);
- }
}
/**
@@ -213,7 +178,7 @@ public final class ChooserTarget implements Parcelable {
*
* @return the icon representing this target, intended to be shown to a user
*/
- public Bitmap getIcon() {
+ public Icon getIcon() {
return mIcon;
}
@@ -241,18 +206,6 @@ public final class ChooserTarget implements Parcelable {
}
/**
- * Returns the Intent supplied by the ChooserTarget's creator.
- * This may be null if the creator specified an IntentSender or PendingIntent instead.
- *
- * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
- *
- * @return the Intent supplied by the ChooserTarget's creator
- */
- public Intent getIntent() {
- return mIntent;
- }
-
- /**
* 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
@@ -272,91 +225,8 @@ public final class ChooserTarget implements Parcelable {
Log.e(TAG, "sendIntent " + this + " failed", e);
return false;
}
- } else if (mIntent != null) {
- try {
- final Intent toSend = new Intent(mIntent);
- toSend.fillIn(fillInIntent, 0);
- context.startActivity(toSend);
- return true;
- } catch (Exception e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
} else {
- Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
- return false;
- }
- }
-
- /**
- * Same as {@link #sendIntent(Context, Intent)}, but offers a userId field to use
- * for launching the {@link #getIntent() intent} using
- * {@link Activity#startActivityAsCaller(Intent, Bundle, int)} if the
- * {@link #getIntentSender() IntentSender} is not present. If the IntentSender is present,
- * it will be invoked as usual with its own calling identity.
- *
- * @hide internal use only.
- */
- public boolean sendIntentAsCaller(Activity context, Intent fillInIntent, int userId) {
- if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
- }
- if (mIntentSender != null) {
- try {
- mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
- return true;
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
- } else if (mIntent != null) {
- try {
- final Intent toSend = new Intent(mIntent);
- toSend.fillIn(fillInIntent, 0);
- context.startActivityAsCaller(toSend, null, userId);
- return true;
- } catch (Exception e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
- } else {
- Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
- return false;
- }
- }
-
- /**
- * The UserHandle is only used if we're launching a raw intent. The IntentSender will be
- * launched with its associated identity.
- *
- * @hide Internal use only
- */
- public boolean sendIntentAsUser(Activity context, Intent fillInIntent, UserHandle user) {
- if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
- }
- if (mIntentSender != null) {
- try {
- mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
- return true;
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
- } else if (mIntent != null) {
- try {
- final Intent toSend = new Intent(mIntent);
- toSend.fillIn(fillInIntent, 0);
- context.startActivityAsUser(toSend, user);
- return true;
- } catch (Exception e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
- } else {
- Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
+ Log.e(TAG, "sendIntent " + this + " failed - no IntentSender to send");
return false;
}
}
@@ -364,7 +234,7 @@ public final class ChooserTarget implements Parcelable {
@Override
public String toString() {
return "ChooserTarget{"
- + (mIntentSender != null ? mIntentSender.getCreatorPackage() : mIntent)
+ + (mIntentSender != null ? mIntentSender.getCreatorPackage() : null)
+ ", "
+ "'" + mTitle
+ "', " + mScore + "}";
@@ -386,10 +256,6 @@ public final class ChooserTarget implements Parcelable {
}
dest.writeFloat(mScore);
IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
- dest.writeInt(mIntent != null ? 1 : 0);
- if (mIntent != null) {
- mIntent.writeToParcel(dest, 0);
- }
}
public static final Creator<ChooserTarget> CREATOR
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
index 699bd0a..0d1834a 100644
--- a/core/java/android/service/chooser/ChooserTargetService.java
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -107,7 +107,7 @@ public abstract class ChooserTargetService extends Service {
* <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>
+ * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.drawable.Icon, 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
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index fc65f63..e99a960 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -79,7 +79,8 @@ public class DynamicLayout extends Layout
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
- spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
+ spacingmult, spacingadd, includepad,
+ StaticLayout.BREAK_STRATEGY_SIMPLE, StaticLayout.HYPHENATION_FREQUENCY_NONE,
ellipsize, ellipsizedWidth);
}
@@ -96,7 +97,7 @@ public class DynamicLayout extends Layout
TextPaint paint,
int width, Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
- boolean includepad, int breakStrategy,
+ boolean includepad, int breakStrategy, int hyphenationFrequency,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
super((ellipsize == null)
? display
@@ -122,6 +123,7 @@ public class DynamicLayout extends Layout
mIncludePad = includepad;
mBreakStrategy = breakStrategy;
+ mHyphenationFrequency = hyphenationFrequency;
/*
* This is annoying, but we can't refer to the layout until
@@ -293,7 +295,8 @@ public class DynamicLayout extends Layout
.setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
.setEllipsizedWidth(mEllipsizedWidth)
.setEllipsize(mEllipsizeAt)
- .setBreakStrategy(mBreakStrategy);
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency);
reflowed.generate(b, false, true);
int n = reflowed.getLineCount();
@@ -719,6 +722,7 @@ public class DynamicLayout extends Layout
private int mEllipsizedWidth;
private TextUtils.TruncateAt mEllipsizeAt;
private int mBreakStrategy;
+ private int mHyphenationFrequency;
private PackedIntVector mInts;
private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 60de02a..f176240 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -71,6 +71,35 @@ public abstract class Layout {
*/
public static final int BREAK_STRATEGY_BALANCED = 2;
+ /** @hide */
+ @IntDef({HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL,
+ HYPHENATION_FREQUENCY_NONE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HyphenationFrequency {}
+
+ /**
+ * Value for hyphenation frequency indicating no automatic hyphenation. Useful
+ * for backward compatibility, and for cases where the automatic hyphenation algorithm results
+ * in incorrect hyphenation. Mid-word breaks may still happen when a word is wider than the
+ * layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
+ * as suggestions for potential line breaks.
+ */
+ public static final int HYPHENATION_FREQUENCY_NONE = 0;
+
+ /**
+ * Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
+ * is a conservative default. Useful for informal cases, such as short sentences or chat
+ * messages.
+ */
+ public static final int HYPHENATION_FREQUENCY_NORMAL = 1;
+
+ /**
+ * Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
+ * in typography. Useful for running text and where it's important to put the maximum amount of
+ * text in a screen with limited space.
+ */
+ public static final int HYPHENATION_FREQUENCY_FULL = 2;
+
private static final ParagraphStyle[] NO_PARA_SPANS =
ArrayUtils.emptyArray(ParagraphStyle.class);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 59c7c6d..d6d046b 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -92,6 +92,7 @@ public class StaticLayout extends Layout {
b.mEllipsize = null;
b.mMaxLines = Integer.MAX_VALUE;
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
+ b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mMeasuredText = MeasuredText.obtain();
return b;
@@ -276,6 +277,19 @@ public class StaticLayout extends Layout {
}
/**
+ * Set hyphenation frequency, to control the amount of automatic hyphenation used. The
+ * default is {@link Layout#HYPHENATION_FREQUENCY_NONE}.
+ *
+ * @param hyphenationFrequency hyphenation frequency for the paragraph
+ * @return this builder, useful for chaining
+ * @see android.widget.TextView#setHyphenationFrequency
+ */
+ public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) {
+ mHyphenationFrequency = hyphenationFrequency;
+ return this;
+ }
+
+ /**
* Set indents. Arguments are arrays holding an indent amount, one per line, measured in
* pixels. For lines past the last element in the array, the last element repeats.
*
@@ -302,7 +316,8 @@ public class StaticLayout extends Layout {
* the native code is as follows.
*
* For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
- * stops, break strategy (and possibly other parameters in the future).
+ * stops, break strategy, and hyphenation frequency (and possibly other parameters in the
+ * future).
*
* Then, for each run within the paragraph:
* - setLocale (this must be done at least for the first run, optional afterwards)
@@ -377,6 +392,7 @@ public class StaticLayout extends Layout {
TextUtils.TruncateAt mEllipsize;
int mMaxLines;
int mBreakStrategy;
+ int mHyphenationFrequency;
Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -644,7 +660,7 @@ public class StaticLayout extends Layout {
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
firstWidth, firstWidthLineCount, restWidth,
- variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
+ variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -1153,7 +1169,7 @@ public class StaticLayout extends Layout {
// Set up paragraph text and settings; done as one big method to minimize jni crossings
private static native void nSetupParagraph(long nativePtr, char[] text, int length,
float firstWidth, int firstWidthLineCount, float restWidth,
- int[] variableTabStops, int defaultTabStop, int breakStrategy);
+ int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency);
private static native float nAddStyleRun(long nativePtr, long nativePaint,
long nativeTypeface, int start, int end, boolean isRtl);
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 68ad782..3781d40 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -586,7 +586,7 @@ final class AccessibilityInteractionController {
}
}
- private void perfromAccessibilityActionUiThread(Message message) {
+ private void performAccessibilityActionUiThread(Message message) {
final int flags = message.arg1;
final int accessibilityViewId = message.arg2;
@@ -602,7 +602,8 @@ final class AccessibilityInteractionController {
boolean succeeded = false;
try {
- if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+ if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null ||
+ mViewRootImpl.mStopped || mViewRootImpl.mPausedForTransition) {
return;
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
@@ -1146,7 +1147,7 @@ final class AccessibilityInteractionController {
findAccessibilityNodeInfoByAccessibilityIdUiThread(message);
} break;
case MSG_PERFORM_ACCESSIBILITY_ACTION: {
- perfromAccessibilityActionUiThread(message);
+ performAccessibilityActionUiThread(message);
} break;
case MSG_FIND_ACCESSIBILITY_NODE_INFOS_BY_VIEW_ID: {
findAccessibilityNodeInfosByViewIdUiThread(message);
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 79a8489..d2b6533 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -209,7 +209,7 @@ public final class Choreographer {
private static float getRefreshRate() {
DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
Display.DEFAULT_DISPLAY);
- return di.refreshRate;
+ return di.getMode().getRefreshRate();
}
/**
diff --git a/core/java/android/view/Display.aidl b/core/java/android/view/Display.aidl
new file mode 100644
index 0000000..42bba44
--- /dev/null
+++ b/core/java/android/view/Display.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.view;
+
+parcelable Display.Mode;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 71e2251..d4b971a 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -21,6 +21,8 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
import android.util.DisplayMetrics;
@@ -619,18 +621,44 @@ public final class Display {
public float getRefreshRate() {
synchronized (this) {
updateDisplayInfoLocked();
- return mDisplayInfo.refreshRate;
+ return mDisplayInfo.getMode().getRefreshRate();
}
}
/**
* Get the supported refresh rates of this display in frames per second.
+ * <p>
+ * This method only returns refresh rates for the display's default modes. For more options, use
+ * {@link #getSupportedModes()}.
+ *
+ * @deprecated use {@link #getSupportedModes()} instead
*/
+ @Deprecated
public float[] getSupportedRefreshRates() {
synchronized (this) {
updateDisplayInfoLocked();
- final float[] refreshRates = mDisplayInfo.supportedRefreshRates;
- return Arrays.copyOf(refreshRates, refreshRates.length);
+ return mDisplayInfo.getDefaultRefreshRates();
+ }
+ }
+
+ /**
+ * Returns the active mode of the display.
+ */
+ public Mode getMode() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.getMode();
+ }
+ }
+
+ /**
+ * Gets the supported modes of this display.
+ */
+ public Mode[] getSupportedModes() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ final Display.Mode[] modes = mDisplayInfo.supportedModes;
+ return Arrays.copyOf(modes, modes.length);
}
}
@@ -862,4 +890,152 @@ public final class Display {
public static boolean isSuspendedState(int state) {
return state == STATE_OFF || state == STATE_DOZE_SUSPEND;
}
+
+ /**
+ * A mode supported by a given display.
+ *
+ * @see Display#getSupportedModes()
+ */
+ public static final class Mode implements Parcelable {
+ /**
+ * @hide
+ */
+ public static final Mode[] EMPTY_ARRAY = new Mode[0];
+
+ private final int mModeId;
+ private final int mWidth;
+ private final int mHeight;
+ private final float mRefreshRate;
+
+ /**
+ * @hide
+ */
+ public Mode(int modeId, int width, int height, float refreshRate) {
+ mModeId = modeId;
+ mWidth = width;
+ mHeight = height;
+ mRefreshRate = refreshRate;
+ }
+
+ /**
+ * Returns this mode's id.
+ */
+ public int getModeId() {
+ return mModeId;
+ }
+
+ /**
+ * Returns the physical width of the display in pixels when configured in this mode's
+ * resolution.
+ * <p>
+ * Note that due to application UI scaling, the number of pixels made available to
+ * applications when the mode is active (as reported by {@link Display#getWidth()} may
+ * differ from the mode's actual resolution (as reported by this function).
+ * <p>
+ * For example, applications running on a 4K display may have their UI laid out and rendered
+ * in 1080p and then scaled up. Applications can take advantage of the extra resolution by
+ * rendering content through a {@link android.view.SurfaceView} using full size buffers.
+ */
+ public int getPhysicalWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Returns the physical height of the display in pixels when configured in this mode's
+ * resolution.
+ * <p>
+ * Note that due to application UI scaling, the number of pixels made available to
+ * applications when the mode is active (as reported by {@link Display#getHeight()} may
+ * differ from the mode's actual resolution (as reported by this function).
+ * <p>
+ * For example, applications running on a 4K display may have their UI laid out and rendered
+ * in 1080p and then scaled up. Applications can take advantage of the extra resolution by
+ * rendering content through a {@link android.view.SurfaceView} using full size buffers.
+ */
+ public int getPhysicalHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Returns the refresh rate in frames per second.
+ */
+ public float getRefreshRate() {
+ return mRefreshRate;
+ }
+
+ /**
+ * Returns {@code true} if this mode matches the given parameters.
+ *
+ * @hide
+ */
+ public boolean matches(int width, int height, float refreshRate) {
+ return mWidth == width &&
+ mHeight == height &&
+ Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Mode)) {
+ return false;
+ }
+ Mode that = (Mode) other;
+ return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 17 + mModeId;
+ hash = hash * 17 + mWidth;
+ hash = hash * 17 + mHeight;
+ hash = hash * 17 + Float.floatToIntBits(mRefreshRate);
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("{")
+ .append("id=").append(mModeId)
+ .append(", width=").append(mWidth)
+ .append(", height=").append(mHeight)
+ .append(", fps=").append(mRefreshRate)
+ .append("}")
+ .toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private Mode(Parcel in) {
+ this(in.readInt(), in.readInt(), in.readInt(), in.readFloat());
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int parcelableFlags) {
+ out.writeInt(mModeId);
+ out.writeInt(mWidth);
+ out.writeInt(mHeight);
+ out.writeFloat(mRefreshRate);
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<Mode> CREATOR
+ = new Parcelable.Creator<Mode>() {
+ @Override
+ public Mode createFromParcel(Parcel in) {
+ return new Mode(in);
+ }
+
+ @Override
+ public Mode[] newArray(int size) {
+ return new Mode[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 243961c..b9fde8a 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -20,11 +20,11 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArraySet;
import android.util.DisplayMetrics;
import java.util.Arrays;
-import libcore.util.EmptyArray;
import libcore.util.Objects;
/**
@@ -155,18 +155,19 @@ public final class DisplayInfo implements Parcelable {
public int rotation;
/**
- * The refresh rate of this display in frames per second.
- * <p>
- * The value of this field is indeterminate if the logical display is presented on
- * more than one physical display.
- * </p>
+ * The active display mode.
+ */
+ public int modeId;
+
+ /**
+ * The default display mode.
*/
- public float refreshRate;
+ public int defaultModeId;
/**
- * The supported refresh rates of this display at the current resolution in frames per second.
+ * The supported modes of this display.
*/
- public float[] supportedRefreshRates = EmptyArray.FLOAT;
+ public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
/**
* The logical display density which is the basis for density-independent
@@ -276,7 +277,8 @@ public final class DisplayInfo implements Parcelable {
&& overscanRight == other.overscanRight
&& overscanBottom == other.overscanBottom
&& rotation == other.rotation
- && refreshRate == other.refreshRate
+ && modeId == other.modeId
+ && defaultModeId == other.defaultModeId
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
@@ -312,9 +314,9 @@ public final class DisplayInfo implements Parcelable {
overscanRight = other.overscanRight;
overscanBottom = other.overscanBottom;
rotation = other.rotation;
- refreshRate = other.refreshRate;
- supportedRefreshRates = Arrays.copyOf(
- other.supportedRefreshRates, other.supportedRefreshRates.length);
+ modeId = other.modeId;
+ defaultModeId = other.defaultModeId;
+ supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
@@ -344,8 +346,13 @@ public final class DisplayInfo implements Parcelable {
overscanRight = source.readInt();
overscanBottom = source.readInt();
rotation = source.readInt();
- refreshRate = source.readFloat();
- supportedRefreshRates = source.createFloatArray();
+ modeId = source.readInt();
+ defaultModeId = source.readInt();
+ int nModes = source.readInt();
+ supportedModes = new Display.Mode[nModes];
+ for (int i = 0; i < nModes; i++) {
+ supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
+ }
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
@@ -377,8 +384,12 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(overscanRight);
dest.writeInt(overscanBottom);
dest.writeInt(rotation);
- dest.writeFloat(refreshRate);
- dest.writeFloatArray(supportedRefreshRates);
+ dest.writeInt(modeId);
+ dest.writeInt(defaultModeId);
+ dest.writeInt(supportedModes.length);
+ for (int i = 0; i < supportedModes.length; i++) {
+ supportedModes[i].writeToParcel(dest, flags);
+ }
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
@@ -395,6 +406,61 @@ public final class DisplayInfo implements Parcelable {
return 0;
}
+ public Display.Mode getMode() {
+ return findMode(modeId);
+ }
+
+ public Display.Mode getDefaultMode() {
+ return findMode(defaultModeId);
+ }
+
+ private Display.Mode findMode(int id) {
+ for (int i = 0; i < supportedModes.length; i++) {
+ if (supportedModes[i].getModeId() == id) {
+ return supportedModes[i];
+ }
+ }
+ throw new IllegalStateException("Unable to locate mode " + id);
+ }
+
+ /**
+ * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
+ * mode could be found.
+ */
+ public int findDefaultModeByRefreshRate(float refreshRate) {
+ Display.Mode[] modes = supportedModes;
+ Display.Mode defaultMode = getDefaultMode();
+ for (int i = 0; i < modes.length; i++) {
+ if (modes[i].matches(
+ defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
+ return modes[i].getModeId();
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the list of supported refresh rates in the default mode.
+ */
+ public float[] getDefaultRefreshRates() {
+ Display.Mode[] modes = supportedModes;
+ ArraySet<Float> rates = new ArraySet<>();
+ Display.Mode defaultMode = getDefaultMode();
+ for (int i = 0; i < modes.length; i++) {
+ Display.Mode mode = modes[i];
+ if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth()
+ && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) {
+ rates.add(mode.getRefreshRate());
+ }
+ }
+ float[] result = new float[rates.size()];
+ int i = 0;
+ for (Float rate : rates) {
+ result[i++] = rate;
+ }
+ return result;
+ }
+
public void getAppMetrics(DisplayMetrics outMetrics) {
getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}
@@ -490,10 +556,12 @@ public final class DisplayInfo implements Parcelable {
sb.append(smallestNominalAppWidth);
sb.append(" x ");
sb.append(smallestNominalAppHeight);
- sb.append(", ");
- sb.append(refreshRate);
- sb.append(" fps, supportedRefreshRates ");
- sb.append(Arrays.toString(supportedRefreshRates));
+ sb.append(", mode ");
+ sb.append(modeId);
+ sb.append(", defaultMode ");
+ sb.append(defaultModeId);
+ sb.append(", modes ");
+ sb.append(Arrays.toString(supportedModes));
sb.append(", rotation ");
sb.append(rotation);
sb.append(", density ");
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 1ac3f45..f6ce353 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1817,9 +1817,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final boolean isWakeKey(int keyCode) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
- case KeyEvent.KEYCODE_POWER:
case KeyEvent.KEYCODE_MENU:
- case KeyEvent.KEYCODE_SLEEP:
case KeyEvent.KEYCODE_WAKEUP:
case KeyEvent.KEYCODE_PAIRING:
return true;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e1f1816..9e16b4b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4265,12 +4265,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
mForegroundInfo.mInsidePadding = a.getBoolean(attr,
mForegroundInfo.mInsidePadding);
+ break;
case R.styleable.View_scrollIndicators:
final int scrollIndicators =
- a.getInt(attr, SCROLL_INDICATORS_NONE) & SCROLL_INDICATORS_PFLAG3_MASK;
+ (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT)
+ & SCROLL_INDICATORS_PFLAG3_MASK;
if (scrollIndicators != 0) {
- viewFlagValues |= scrollIndicators;
- viewFlagMasks |= SCROLL_INDICATORS_PFLAG3_MASK;
+ mPrivateFlags3 |= scrollIndicators;
initializeScrollIndicators = true;
}
break;
@@ -4884,7 +4885,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_scrollIndicators
*/
public void setScrollIndicators(@ScrollIndicators int indicators) {
- setScrollIndicators(indicators, SCROLL_INDICATORS_PFLAG3_MASK);
+ setScrollIndicators(indicators,
+ SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT);
}
/**
@@ -4954,36 +4956,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
>>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
}
- /**
- * Returns whether the specified scroll indicator is enabled.
- * <p>
- * Multiple indicator types may be queried by passing the logical OR of the
- * desired types. If multiple types are specified, the return value
- * represents whether they are all enabled.
- *
- * @param direction the indicator direction, or the logical OR of multiple
- * indicator directions. One or more of:
- * <ul>
- * <li>{@link #SCROLL_INDICATOR_TOP}</li>
- * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li>
- * <li>{@link #SCROLL_INDICATOR_LEFT}</li>
- * <li>{@link #SCROLL_INDICATOR_RIGHT}</li>
- * <li>{@link #SCROLL_INDICATOR_START}</li>
- * <li>{@link #SCROLL_INDICATOR_END}</li>
- * </ul>
- * @return {@code true} if the specified indicator(s) are enabled,
- * {@code false} otherwise
- * @attr ref android.R.styleable#View_scrollIndicators
- */
- public boolean isScrollIndicatorEnabled(int direction) {
- // Shift and sanitize input.
- direction <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT;
- direction &= SCROLL_INDICATORS_PFLAG3_MASK;
-
- // All of the flags must be set.
- return (mPrivateFlags3 & direction) == direction;
- }
-
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 51c4760..b476e9b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -586,6 +586,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
mGroupFlags |= FLAG_CLIP_CHILDREN;
mGroupFlags |= FLAG_CLIP_TO_PADDING;
mGroupFlags |= FLAG_ANIMATION_DONE;
+ mGroupFlags |= FLAG_ANIMATION_CACHE;
+ mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ea1dadb..57c6cbf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -174,6 +174,9 @@ public final class ViewRootImpl implements ViewParent,
// so the window should no longer be active.
boolean mStopped = false;
+ // Set to true to stop input during an Activity Transition.
+ boolean mPausedForTransition = false;
+
boolean mLastInCompatMode = false;
SurfaceHolder.Callback2 mSurfaceHolderCallback;
@@ -982,15 +985,25 @@ public final class ViewRootImpl implements ViewParent,
return null;
}
- void setStopped(boolean stopped) {
+ void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
- if (!stopped) {
+ if (!mStopped) {
scheduleTraversals();
}
}
}
+ /**
+ * Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
+ * through to allow quick reversal of the Activity Transition.
+ *
+ * @param paused true to pause, false to resume.
+ */
+ public void setPausedForTransition(boolean paused) {
+ mPausedForTransition = paused;
+ }
+
@Override
public ViewParent getParent() {
return null;
@@ -3637,8 +3650,9 @@ public final class ViewRootImpl implements ViewParent,
if (mView == null || !mAdded) {
Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
return true;
- } else if ((!mAttachInfo.mHasWindowFocus || mStopped)
- && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+ } else if ((!mAttachInfo.mHasWindowFocus
+ && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
+ || (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
// has stopped. This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
@@ -3661,6 +3675,14 @@ public final class ViewRootImpl implements ViewParent,
mNext.dump(prefix, writer);
}
}
+
+ private boolean isBack(InputEvent event) {
+ if (event instanceof KeyEvent) {
+ return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
+ } else {
+ return false;
+ }
+ }
}
/**
@@ -6228,7 +6250,7 @@ public final class ViewRootImpl implements ViewParent,
@Override
public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
- if (mView == null) {
+ if (mView == null || mStopped || mPausedForTransition) {
return false;
}
// Intercept accessibility focus events fired by virtual nodes to keep
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2797b6e..7976ca4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -101,7 +101,7 @@ public interface WindowManager extends ViewManager {
* the given view hierarchy's {@link View#onDetachedFromWindow()
* View.onDetachedFromWindow()} methods before returning. This is not
* for normal applications; using it correctly requires great care.
- *
+ *
* @param view The view to be removed.
*/
public void removeViewImmediate(View view);
@@ -115,7 +115,7 @@ public interface WindowManager extends ViewManager {
*/
@ViewDebug.ExportedProperty
public int x;
-
+
/**
* Y position for this window. With the default gravity it is ignored.
* When using {@link Gravity#TOP} or {@link Gravity#BOTTOM} it provides
@@ -228,12 +228,12 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
})
public int type;
-
+
/**
* Start of window types that represent normal application windows.
*/
public static final int FIRST_APPLICATION_WINDOW = 1;
-
+
/**
* Window type: an application window that serves as the "base" window
* of the overall application; all other application windows will
@@ -241,14 +241,14 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_BASE_APPLICATION = 1;
-
+
/**
* Window type: a normal application window. The {@link #token} must be
* an Activity token identifying who the window belongs to.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_APPLICATION = 2;
-
+
/**
* Window type: special application window that is displayed while the
* application is starting. Not for use by applications themselves;
@@ -257,7 +257,7 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_APPLICATION_STARTING = 3;
-
+
/**
* End of types of application windows.
*/
@@ -330,14 +330,14 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
-
+
/**
* Window type: the search bar. There can be only one search bar
* window; it is placed at the top of the screen.
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
-
+
/**
* Window type: phone. These are non-application windows providing
* user interaction with the phone (in particular incoming calls).
@@ -346,7 +346,7 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
-
+
/**
* Window type: system window, such as low power alert. These windows
* are always on top of application windows.
@@ -366,7 +366,7 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
-
+
/**
* Window type: system overlay windows, which need to be displayed
* on top of everything else. These windows must not take input
@@ -374,7 +374,7 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;
-
+
/**
* Window type: priority phone UI, which needs to be displayed even if
* the keyguard is active. These windows must not take input
@@ -382,26 +382,26 @@ public interface WindowManager extends ViewManager {
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
-
+
/**
* Window type: panel that slides out from the status bar
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8;
-
+
/**
* Window type: dialogs that the keyguard shows
* In multiuser systems shows on all users' windows.
*/
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9;
-
+
/**
* Window type: internal system error windows, appear on top of
* everything they can.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;
-
+
/**
* Window type: internal input methods windows, which appear above
* the normal UI. Application windows may be resized or panned to keep
@@ -581,16 +581,16 @@ public interface WindowManager extends ViewManager {
/** @deprecated this is ignored, this value is set automatically when needed. */
@Deprecated
public static final int MEMORY_TYPE_PUSH_BUFFERS = 3;
-
+
/**
* @deprecated this is ignored
*/
@Deprecated
public int memoryType;
-
+
/** Window flag: as long as this window is visible to the user, allow
- * the lock screen to activate while the screen is on.
- * This can be used independently, or in combination with
+ * the lock screen to activate while the screen is on.
+ * This can be used independently, or in combination with
* {@link #FLAG_KEEP_SCREEN_ON} and/or {@link #FLAG_SHOW_WHEN_LOCKED} */
public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001;
@@ -608,26 +608,26 @@ public interface WindowManager extends ViewManager {
* instead go to whatever focusable window is behind it. This flag
* will also enable {@link #FLAG_NOT_TOUCH_MODAL} whether or not that
* is explicitly set.
- *
+ *
* <p>Setting this flag also implies that the window will not need to
* interact with
- * a soft input method, so it will be Z-ordered and positioned
+ * a soft input method, so it will be Z-ordered and positioned
* independently of any active input method (typically this means it
* gets Z-ordered on top of the input method, so it can use the full
* screen for its content and cover the input method if needed. You
* can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
public static final int FLAG_NOT_FOCUSABLE = 0x00000008;
-
+
/** Window flag: this window can never receive touch events. */
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;
-
+
/** Window flag: even when this window is focusable (its
* {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events
* outside of the window to be sent to the windows behind it. Otherwise
* it will consume all pointer events itself, regardless of whether they
* are inside of the window. */
public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;
-
+
/** Window flag: when set, if the device is asleep when the touch
* screen is pressed, you will receive this first touch event. Usually
* the first touch event is consumed by the system since the user can
@@ -637,21 +637,21 @@ public interface WindowManager extends ViewManager {
*/
@Deprecated
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
-
+
/** Window flag: as long as this window is visible to the user, keep
* the device's screen turned on and bright. */
public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;
-
+
/** Window flag: place the window within the entire screen, ignoring
* decorations around the border (such as the status bar). The
* window must correctly position its contents to take the screen
* decoration into account. This flag is normally set for you
* by Window as described in {@link Window#setFlags}. */
public static final int FLAG_LAYOUT_IN_SCREEN = 0x00000100;
-
+
/** Window flag: allow window to extend outside of the screen. */
public static final int FLAG_LAYOUT_NO_LIMITS = 0x00000200;
-
+
/**
* Window flag: hide all screen decorations (such as the status bar) while
* this window is displayed. This allows the window to use the entire
@@ -673,17 +673,17 @@ public interface WindowManager extends ViewManager {
* {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_Fullscreen}.</p>
*/
public static final int FLAG_FULLSCREEN = 0x00000400;
-
+
/** Window flag: override {@link #FLAG_FULLSCREEN} and force the
* screen decorations (such as the status bar) to be shown. */
public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;
-
+
/** Window flag: turn on dithering when compositing this window to
* the screen.
* @deprecated This flag is no longer used. */
@Deprecated
public static final int FLAG_DITHER = 0x00001000;
-
+
/** Window flag: treat the content of the window as secure, preventing
* it from appearing in screenshots or from being viewed on non-secure
* displays.
@@ -692,21 +692,21 @@ public interface WindowManager extends ViewManager {
* secure surfaces and secure displays.
*/
public static final int FLAG_SECURE = 0x00002000;
-
+
/** Window flag: a special mode where the layout parameters are used
* to perform scaling of the surface when it is composited to the
* screen. */
public static final int FLAG_SCALED = 0x00004000;
-
+
/** Window flag: intended for windows that will often be used when the user is
* holding the screen against their face, it will aggressively filter the event
* stream to prevent unintended presses in this situation that may not be
- * desired for a particular window, when such an event stream is detected, the
+ * desired for a particular window, when such an event stream is detected, the
* application will receive a CANCEL motion event to indicate this so applications
- * can handle this accordingly by taking no action on the event
+ * can handle this accordingly by taking no action on the event
* until the finger is released. */
public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;
-
+
/** Window flag: a special option only for use in combination with
* {@link #FLAG_LAYOUT_IN_SCREEN}. When requesting layout in the
* screen your window may appear on top of or behind screen decorations
@@ -715,7 +715,7 @@ public interface WindowManager extends ViewManager {
* content is not covered by screen decorations. This flag is normally
* set for you by Window as described in {@link Window#setFlags}.*/
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
-
+
/** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with
* respect to how this window interacts with the current method. That
* is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the
@@ -726,7 +726,7 @@ public interface WindowManager extends ViewManager {
* to use more space and cover the input method.
*/
public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
-
+
/** Window flag: if you have set {@link #FLAG_NOT_TOUCH_MODAL}, you
* can set this flag to receive a single special MotionEvent with
* the action
@@ -736,7 +736,7 @@ public interface WindowManager extends ViewManager {
* first down as an ACTION_OUTSIDE.
*/
public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;
-
+
/** Window flag: special flag to let windows be shown when the screen
* is locked. This will let application windows take precedence over
* key guard or any other lock screens. Can be used with
@@ -766,13 +766,13 @@ public interface WindowManager extends ViewManager {
* {@link android.R.style#Theme_DeviceDefault_Wallpaper_NoTitleBar}.</p>
*/
public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
-
+
/** Window flag: when set as a window is being added or made
* visible, once the window has been shown then the system will
* poke the power manager's user activity (as if the user had woken
* up the device) to turn the screen on. */
public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
-
+
/** Window flag: when set the window will cause the keyguard to
* be dismissed, only if it is not a secure lock keyguard. Because such
* a keyguard is not needed for security, it will never re-appear if
@@ -786,7 +786,7 @@ public interface WindowManager extends ViewManager {
* also been set.
*/
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
-
+
/** Window flag: when set the window will accept for touch events
* outside of its bounds to be sent to other windows that also
* support split touch. When this flag is not set, the first pointer
@@ -798,7 +798,7 @@ public interface WindowManager extends ViewManager {
* to be split across multiple windows.
*/
public static final int FLAG_SPLIT_TOUCH = 0x00800000;
-
+
/**
* <p>Indicates whether this window should be hardware accelerated.
* Requesting hardware acceleration does not guarantee it will happen.</p>
@@ -940,7 +940,7 @@ public interface WindowManager extends ViewManager {
/**
* Various behavioral options/flags. Default is none.
- *
+ *
* @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
* @see #FLAG_DIM_BEHIND
* @see #FLAG_NOT_FOCUSABLE
@@ -1041,10 +1041,10 @@ public interface WindowManager extends ViewManager {
* as if it was.
* Like {@link #FLAG_HARDWARE_ACCELERATED} except for trusted system windows
* that need hardware acceleration (e.g. LockScreen), where hardware acceleration
- * is generally disabled. This flag must be specified in addition to
+ * is generally disabled. This flag must be specified in addition to
* {@link #FLAG_HARDWARE_ACCELERATED} to enable hardware acceleration for system
* windows.
- *
+ *
* @hide
*/
public static final int PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED = 0x00000001;
@@ -1055,7 +1055,7 @@ public interface WindowManager extends ViewManager {
* If certain parts of the UI that really do want to use hardware
* acceleration, this flag can be set to force it. This is basically
* for the lock screen. Anyone else using it, you are probably wrong.
- *
+ *
* @hide
*/
public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 0x00000002;
@@ -1194,63 +1194,63 @@ public interface WindowManager extends ViewManager {
}
return false;
}
-
+
/**
* Mask for {@link #softInputMode} of the bits that determine the
* desired visibility state of the soft input area for this window.
*/
public static final int SOFT_INPUT_MASK_STATE = 0x0f;
-
+
/**
* Visibility state for {@link #softInputMode}: no state has been specified.
*/
public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
-
+
/**
* Visibility state for {@link #softInputMode}: please don't change the state of
* the soft input area.
*/
public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
-
+
/**
* Visibility state for {@link #softInputMode}: please hide any soft input
* area when normally appropriate (when the user is navigating
* forward to your window).
*/
public static final int SOFT_INPUT_STATE_HIDDEN = 2;
-
+
/**
* Visibility state for {@link #softInputMode}: please always hide any
* soft input area when this window receives focus.
*/
public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
-
+
/**
* Visibility state for {@link #softInputMode}: please show the soft
* input area when normally appropriate (when the user is navigating
* forward to your window).
*/
public static final int SOFT_INPUT_STATE_VISIBLE = 4;
-
+
/**
* Visibility state for {@link #softInputMode}: please always make the
* soft input area visible when this window receives input focus.
*/
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
-
+
/**
* Mask for {@link #softInputMode} of the bits that determine the
* way that the window should be adjusted to accommodate the soft
* input window.
*/
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
-
+
/** Adjustment option for {@link #softInputMode}: nothing specified.
* The system will try to pick one or
* the other depending on the contents of the window.
*/
public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
-
+
/** Adjustment option for {@link #softInputMode}: set to allow the
* window to be resized when an input
* method is shown, so that its contents are not covered by the input
@@ -1263,7 +1263,7 @@ public interface WindowManager extends ViewManager {
* not resize, but will stay fullscreen.
*/
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
-
+
/** Adjustment option for {@link #softInputMode}: set to have a window
* pan when an input method is
* shown, so it doesn't need to deal with resizing but just panned
@@ -1273,7 +1273,7 @@ public interface WindowManager extends ViewManager {
* the other depending on the contents of the window.
*/
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
-
+
/** Adjustment option for {@link #softInputMode}: set to have a window
* not adjust for a shown input method. The window will not be resized,
* and it will not be panned to make its focus visible.
@@ -1292,7 +1292,7 @@ public interface WindowManager extends ViewManager {
/**
* Desired operating mode for any soft input area. May be any combination
* of:
- *
+ *
* <ul>
* <li> One of the visibility states
* {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED},
@@ -1309,7 +1309,7 @@ public interface WindowManager extends ViewManager {
* {@link android.R.attr#windowSoftInputMode} attribute.</p>
*/
public int softInputMode;
-
+
/**
* Placement of window within the screen as per {@link Gravity}. Both
* {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
@@ -1326,7 +1326,7 @@ public interface WindowManager extends ViewManager {
* @see Gravity
*/
public int gravity;
-
+
/**
* The horizontal margin, as a percentage of the container's width,
* between the container and the widget. See
@@ -1335,7 +1335,7 @@ public interface WindowManager extends ViewManager {
* field is added with {@link #x} to supply the <var>xAdj</var> parameter.
*/
public float horizontalMargin;
-
+
/**
* The vertical margin, as a percentage of the container's height,
* between the container and the widget. See
@@ -1361,26 +1361,26 @@ public interface WindowManager extends ViewManager {
* @hide
*/
public boolean hasManualSurfaceInsets;
-
+
/**
* The desired bitmap format. May be one of the constants in
* {@link android.graphics.PixelFormat}. Default is OPAQUE.
*/
public int format;
-
+
/**
* A style resource defining the animations to use for this window.
* This must be a system resource; it can not be an application resource
* because the window manager does not have access to applications.
*/
public int windowAnimations;
-
+
/**
* An alpha value to apply to this entire window.
* An alpha of 1.0 means fully opaque and 0.0 means fully transparent
*/
public float alpha = 1.0f;
-
+
/**
* When {@link #FLAG_DIM_BEHIND} is set, this is the amount of dimming
* to apply. Range is from 1.0 for completely opaque to 0.0 for no
@@ -1408,7 +1408,7 @@ public interface WindowManager extends ViewManager {
* to the hightest value when this window is in front.
*/
public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
-
+
/**
* This can be used to override the user's preferred brightness of
* the screen. A value of less than 0, the default, means to use the
@@ -1416,7 +1416,7 @@ public interface WindowManager extends ViewManager {
* dark to full bright.
*/
public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
-
+
/**
* This can be used to override the standard behavior of the button and
* keyboard backlights. A value of less than 0, the default, means to
@@ -1450,7 +1450,7 @@ public interface WindowManager extends ViewManager {
* opaque windows have the #FLAG_FULLSCREEN bit set and are not covered
* by other windows. All other situations default to the
* {@link #ROTATION_ANIMATION_ROTATE} behavior.
- *
+ *
* @see #ROTATION_ANIMATION_ROTATE
* @see #ROTATION_ANIMATION_CROSSFADE
* @see #ROTATION_ANIMATION_JUMPCUT
@@ -1462,18 +1462,18 @@ public interface WindowManager extends ViewManager {
* you.
*/
public IBinder token = null;
-
+
/**
* Name of the package owning this window.
*/
public String packageName = null;
-
+
/**
* Specific orientation value for a window.
* May be any of the same values allowed
- * for {@link android.content.pm.ActivityInfo#screenOrientation}.
- * If not set, a default value of
- * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}
+ * for {@link android.content.pm.ActivityInfo#screenOrientation}.
+ * If not set, a default value of
+ * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}
* will be used.
*/
public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -1482,13 +1482,28 @@ public interface WindowManager extends ViewManager {
* The preferred refresh rate for the window.
*
* This must be one of the supported refresh rates obtained for the display(s) the window
- * is on.
+ * is on. The selected refresh rate will be applied to the display's default mode.
+ *
+ * This value is ignored if {@link #preferredDisplayModeId} is set.
*
* @see Display#getSupportedRefreshRates()
+ * @deprecated use {@link #preferredDisplayModeId} instead
*/
+ @Deprecated
public float preferredRefreshRate;
/**
+ * Id of the preferred display mode for the window.
+ * <p>
+ * This must be one of the supported modes obtained for the display(s) the window is on.
+ * A value of {@code 0} means no preference.
+ *
+ * @see Display#getSupportedModes()
+ * @see Display.Mode#getModeId()
+ */
+ public int preferredDisplayModeId;
+
+ /**
* Control the visibility of the status bar.
*
* @see View#STATUS_BAR_VISIBLE
@@ -1505,7 +1520,7 @@ public interface WindowManager extends ViewManager {
/**
* Get callbacks about the system ui visibility changing.
- *
+ *
* TODO: Maybe there should be a bitfield of optional callbacks that we need.
*
* @hide
@@ -1571,34 +1586,34 @@ public interface WindowManager extends ViewManager {
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
-
+
public LayoutParams(int _type) {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = _type;
format = PixelFormat.OPAQUE;
}
-
+
public LayoutParams(int _type, int _flags) {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = _type;
flags = _flags;
format = PixelFormat.OPAQUE;
}
-
+
public LayoutParams(int _type, int _flags, int _format) {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = _type;
flags = _flags;
format = _format;
}
-
+
public LayoutParams(int w, int h, int _type, int _flags, int _format) {
super(w, h);
type = _type;
flags = _flags;
format = _format;
}
-
+
public LayoutParams(int w, int h, int xpos, int ypos, int _type,
int _flags, int _format) {
super(w, h);
@@ -1608,14 +1623,14 @@ public interface WindowManager extends ViewManager {
flags = _flags;
format = _format;
}
-
+
public final void setTitle(CharSequence title) {
if (null == title)
title = "";
-
+
mTitle = TextUtils.stringOrSpannedString(title);
}
-
+
public final CharSequence getTitle() {
return mTitle;
}
@@ -1660,6 +1675,7 @@ public interface WindowManager extends ViewManager {
TextUtils.writeToParcel(mTitle, out, parcelableFlags);
out.writeInt(screenOrientation);
out.writeFloat(preferredRefreshRate);
+ out.writeInt(preferredDisplayModeId);
out.writeInt(systemUiVisibility);
out.writeInt(subtreeSystemUiVisibility);
out.writeInt(hasSystemUiListeners ? 1 : 0);
@@ -1683,8 +1699,8 @@ public interface WindowManager extends ViewManager {
return new LayoutParams[size];
}
};
-
-
+
+
public LayoutParams(Parcel in) {
width = in.readInt();
height = in.readInt();
@@ -1709,6 +1725,7 @@ public interface WindowManager extends ViewManager {
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
screenOrientation = in.readInt();
preferredRefreshRate = in.readFloat();
+ preferredDisplayModeId = in.readInt();
systemUiVisibility = in.readInt();
subtreeSystemUiVisibility = in.readInt();
hasSystemUiListeners = in.readInt() != 0;
@@ -1757,6 +1774,8 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22;
/** {@hide} */
+ public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
+ /** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -1863,7 +1882,7 @@ public interface WindowManager extends ViewManager {
rotationAnimation = o.rotationAnimation;
changes |= ROTATION_ANIMATION_CHANGED;
}
-
+
if (screenOrientation != o.screenOrientation) {
screenOrientation = o.screenOrientation;
changes |= SCREEN_ORIENTATION_CHANGED;
@@ -1874,6 +1893,11 @@ public interface WindowManager extends ViewManager {
changes |= PREFERRED_REFRESH_RATE_CHANGED;
}
+ if (preferredDisplayModeId != o.preferredDisplayModeId) {
+ preferredDisplayModeId = o.preferredDisplayModeId;
+ changes |= PREFERRED_DISPLAY_MODE_ID;
+ }
+
if (systemUiVisibility != o.systemUiVisibility
|| subtreeSystemUiVisibility != o.subtreeSystemUiVisibility) {
systemUiVisibility = o.systemUiVisibility;
@@ -1924,7 +1948,7 @@ public interface WindowManager extends ViewManager {
Log.d("Debug", "WindowManager.LayoutParams={title=" + mTitle + "}");
return "";
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(256);
@@ -1996,6 +2020,10 @@ public interface WindowManager extends ViewManager {
sb.append(" preferredRefreshRate=");
sb.append(preferredRefreshRate);
}
+ if (preferredDisplayModeId != 0) {
+ sb.append(" preferredDisplayMode=");
+ sb.append(preferredDisplayModeId);
+ }
if (systemUiVisibility != 0) {
sb.append(" sysui=0x");
sb.append(Integer.toHexString(systemUiVisibility));
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 57558ff..e7a7ba8 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -21,7 +21,6 @@ import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -552,7 +551,7 @@ public final class WindowManagerGlobal {
for (int i = 0; i < count; i++) {
if (token == null || mParams.get(i).token == token) {
ViewRootImpl root = mRoots.get(i);
- root.setStopped(stopped);
+ root.setWindowStopped(stopped);
}
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 040fd37..568e160 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -350,16 +350,6 @@ public final class InputMethodManager {
*/
private CursorAnchorInfo mCursorAnchorInfo = null;
- /**
- * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}.
- */
- private final int[] mViewTopLeft = new int[2];
-
- /**
- * The matrix to convert the view location into screen coordinates in {@link #updateCursor}.
- */
- private final Matrix mViewToScreenMatrix = new Matrix();
-
// -----------------------------------------------------------
/**
diff --git a/core/java/android/webkit/ViewAssistStructure.java b/core/java/android/webkit/ViewAssistStructure.java
new file mode 100644
index 0000000..6f7a645
--- /dev/null
+++ b/core/java/android/webkit/ViewAssistStructure.java
@@ -0,0 +1,203 @@
+/*
+ * 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 android.graphics.Rect;
+import android.os.Bundle;
+import android.text.TextPaint;
+import android.view.ViewStructure;
+
+
+/**
+ * TODO This class is temporary. It will be deleted once we update Webview APK to use the
+ * new ViewStructure method.
+ * @hide
+ */
+public class ViewAssistStructure extends android.view.ViewAssistStructure {
+
+ private ViewStructure mV;
+
+ public ViewAssistStructure(ViewStructure v) {
+ mV = v;
+ }
+
+ @Override
+ public void setId(int id, String packageName, String typeName, String entryName) {
+ mV.setId(id, packageName, typeName, entryName);
+ }
+
+ @Override
+ public void setDimens(int left, int top, int scrollX, int scrollY, int width,
+ int height) {
+ mV.setDimens(left, top, scrollX, scrollY, width, height);
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ mV.setVisibility(visibility);
+ }
+
+ @Override
+ public void setAssistBlocked(boolean state) {
+ mV.setAssistBlocked(state);
+ }
+
+ @Override
+ public void setEnabled(boolean state) {
+ mV.setEnabled(state);
+ }
+
+ @Override
+ public void setClickable(boolean state) {
+ mV.setClickable(state);
+ }
+
+ @Override
+ public void setLongClickable(boolean state) {
+ mV.setLongClickable(state);
+ }
+
+ @Override
+ public void setStylusButtonPressable(boolean state) {
+ mV.setStylusButtonPressable(state);
+ }
+
+ @Override
+ public void setFocusable(boolean state) {
+ mV.setFocusable(state);
+ }
+
+ @Override
+ public void setFocused(boolean state) {
+ mV.setFocused(state);
+ }
+
+ @Override
+ public void setAccessibilityFocused(boolean state) {
+ mV.setAccessibilityFocused(state);
+ }
+
+ @Override
+ public void setCheckable(boolean state) {
+ mV.setCheckable(state);
+ }
+
+ @Override
+ public void setChecked(boolean state) {
+ mV.setChecked(state);
+ }
+
+ @Override
+ public void setSelected(boolean state) {
+ mV.setSelected(state);
+ }
+
+ @Override
+ public void setActivated(boolean state) {
+ mV.setActivated(state);
+ }
+
+ @Override
+ public void setClassName(String className) {
+ mV.setClassName(className);
+ }
+
+ @Override
+ public void setContentDescription(CharSequence contentDescription) {
+ mV.setContentDescription(contentDescription);
+ }
+
+ @Override
+ public void setText(CharSequence text) {
+ mV.setText(text);
+ }
+
+ @Override
+ public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+ mV.setText(text, selectionStart, selectionEnd);
+ }
+
+ @Override
+ public void setTextPaint(TextPaint paint) {
+ mV.setTextPaint(paint);
+ }
+
+ @Override
+ public void setHint(CharSequence hint) {
+ mV.setHint(hint);
+ }
+
+ @Override
+ public CharSequence getText() {
+ return mV.getText();
+ }
+
+ @Override
+ public int getTextSelectionStart() {
+ return mV.getTextSelectionStart();
+ }
+
+ @Override
+ public int getTextSelectionEnd() {
+ return mV.getTextSelectionEnd();
+ }
+
+ @Override
+ public CharSequence getHint() {
+ return mV.getHint();
+ }
+
+ @Override
+ public Bundle getExtras() {
+ return mV.getExtras();
+ }
+
+ @Override
+ public boolean hasExtras() {
+ return mV.hasExtras();
+ }
+
+ @Override
+ public void setChildCount(int num) {
+ mV.setChildCount(num);
+ }
+
+ @Override
+ public int getChildCount() {
+ return mV.getChildCount();
+ }
+
+ @Override
+ public android.view.ViewAssistStructure newChild(int index) {
+ return mV.newChild(index);
+ }
+
+ @Override
+ public android.view.ViewAssistStructure asyncNewChild(int index) {
+ return mV.asyncNewChild(index);
+ }
+
+ @Override
+ public void asyncCommit() {
+ mV.asyncCommit();
+ }
+
+ @Override
+ public Rect getTempRect() {
+ return mV.getTempRect();
+ }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e27e253..f990e41 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -366,15 +366,15 @@ public class WebView extends AbsoluteLayout
}
/**
- * Callback interface supplied to {@link #insertVisualStateCallback} for receiving
+ * Callback interface supplied to {@link #postVisualStateCallback} for receiving
* notifications about the visual state.
*/
public static abstract class VisualStateCallback {
/**
* Invoked when the visual state is ready to be drawn in the next {@link #onDraw}.
*
- * @param requestId the id supplied to the corresponding {@link #insertVisualStateCallback}
- * request
+ * @param requestId The identifier passed to {@link #postVisualStateCallback} when this
+ * callback was posted.
*/
public abstract void onComplete(long requestId);
}
@@ -1125,15 +1125,18 @@ public class WebView extends AbsoluteLayout
}
/**
- * Inserts a {@link VisualStateCallback}.
+ * Posts a {@link VisualStateCallback}, which will be called when
+ * the current state of the WebView is ready to be drawn.
*
- * <p>Updates to the the DOM are reflected asynchronously such that when the DOM is updated the
- * subsequent {@link WebView#onDraw} invocation might not reflect those updates. The
+ * <p>Because updates to the the DOM are processed asynchronously, updates to the DOM may not
+ * immediately be reflected visually by subsequent {@link WebView#onDraw} invocations. The
* {@link VisualStateCallback} provides a mechanism to notify the caller when the contents of
- * the DOM at the current time are ready to be drawn the next time the {@link WebView} draws.
- * By current time we mean the time at which this API was called. The next draw after the
- * callback completes is guaranteed to reflect all the updates to the DOM applied before the
- * current time, but it may also contain updates applied after the current time.</p>
+ * the DOM at the current time are ready to be drawn the next time the {@link WebView}
+ * draws.</p>
+ *
+ * <p>The next draw after the callback completes is guaranteed to reflect all the updates to the
+ * DOM up to the the point at which the {@link VisualStateCallback} was posted, but it may also
+ * contain updates applied after the callback was posted.</p>
*
* <p>The state of the DOM covered by this API includes the following:
* <ul>
@@ -1164,15 +1167,15 @@ public class WebView extends AbsoluteLayout
* {@link VisualStateCallback#onComplete} method.</li>
* </ul></p>
*
- * <p>When using this API it is also recommended to enable pre-rasterization if the
- * {@link WebView} is offscreen to avoid flickering. See WebSettings#setOffscreenPreRaster for
+ * <p>When using this API it is also recommended to enable pre-rasterization if the {@link
+ * WebView} is offscreen to avoid flickering. See {@link WebSettings#setOffscreenPreRaster} for
* more details and do consider its caveats.</p>
*
- * @param requestId an id that will be returned in the callback to allow callers to match
- * requests with callbacks.
- * @param callback the callback to be invoked.
+ * @param requestId An id that will be returned in the callback to allow callers to match
+ * requests with callbacks.
+ * @param callback The callback to be invoked.
*/
- public void insertVisualStateCallback(long requestId, VisualStateCallback callback) {
+ public void postVisualStateCallback(long requestId, VisualStateCallback callback) {
checkThread();
mProvider.insertVisualStateCallback(requestId, callback);
}
@@ -2429,7 +2432,8 @@ public class WebView extends AbsoluteLayout
@Override
public void onProvideVirtualStructure(ViewStructure structure) {
- mProvider.getViewDelegate().onProvideVirtualAssistStructure(structure);
+ ViewAssistStructure s = new ViewAssistStructure(structure);
+ mProvider.getViewDelegate().onProvideVirtualAssistStructure(s);
}
/** @hide */
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 8a2b3fa..3a40de6 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -83,27 +83,31 @@ public class WebViewClient {
}
/**
- * Notify the host application that the page commit is visible.
+ * Notify the host application that {@link android.webkit.WebView} content left over from
+ * previous page navigations will no longer be drawn.
*
- * <p>This is the earliest point at which we can guarantee that the contents of the previously
- * loaded page will not longer be drawn in the next {@link WebView#onDraw}. The next draw will
- * render the {@link WebView#setBackgroundColor background color} of the WebView or some of the
- * contents from the committed page already. This callback may be useful when reusing
- * {@link WebView}s to ensure that no stale content is shown. This method is only called for
- * the main frame.</p>
+ * <p>This callback can be used to determine the point at which it is safe to make a recycled
+ * {@link android.webkit.WebView} visible, ensuring that no stale content is shown. It is called
+ * at the earliest point at which it can be guaranteed that {@link WebView#onDraw} will no
+ * longer draw any content from previous navigations. The next draw will display either the
+ * {@link WebView#setBackgroundColor background color} of the {@link WebView}, or some of the
+ * contents of the newly loaded page.
*
- * <p>This method is called when the state of the DOM at the point at which the
- * body of the HTTP response (commonly the string of html) had started loading will be visible.
- * If you set a background color for the page in the HTTP response body this will most likely
- * be visible and perhaps some other elements. At that point no other resources had usually
- * been loaded, so you can expect images for example to not be visible. If you want
- * a finer level of granularity consider calling {@link WebView#insertVisualStateCallback}
- * directly.</p>
+ * <p>This method is called when the body of the HTTP response has started loading, is reflected
+ * in the DOM, and will be visible in subsequent draws. This callback occurs early in the
+ * document loading process, and as such you should expect that linked resources (for example,
+ * css and images) may not be available.</p>
*
- * <p>Please note that all the conditions and recommendations presented in
- * {@link WebView#insertVisualStateCallback} also apply to this API.<p>
+ * <p>For more fine-grained notification of visual state updates, see {@link
+ * WebView#postVisualStateCallback}.</p>
*
- * @param url the url of the committed page
+ * <p>Please note that all the conditions and recommendations applicable to
+ * {@link WebView#postVisualStateCallback} also apply to this API.<p>
+ *
+ * <p>This callback is only called for main frame navigations.</p>
+ *
+ * @param view The {@link android.webkit.WebView} for which the navigation occurred.
+ * @param url The URL corresponding to the page navigation that triggered this callback.
*/
public void onPageCommitVisible(WebView view, String url) {
}
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index e367192..00aba2a 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -32,7 +32,6 @@ import android.print.PrintDocumentAdapter;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewStructure;
import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -299,7 +298,7 @@ public interface WebViewProvider {
interface ViewDelegate {
public boolean shouldDelayChildPressedState();
- public void onProvideVirtualAssistStructure(ViewStructure structure);
+ public void onProvideVirtualAssistStructure(android.view.ViewAssistStructure structure);
public AccessibilityNodeProvider getAccessibilityNodeProvider();
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 6feb94b..bb4a948 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -244,7 +244,7 @@ public class AppSecurityPermissions {
@Override
public void onClick(DialogInterface dialog, int which) {
PackageManager pm = getContext().getPackageManager();
- pm.revokePermission(mPackageName, mPerm.name,
+ pm.revokeRuntimePermission(mPackageName, mPerm.name,
new UserHandle(mContext.getUserId()));
PermissionItemView.this.setVisibility(View.GONE);
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4fd85b6..c81e2f0 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3902,6 +3902,9 @@ public class Editor {
@Override
public void updatePosition(float x, float y) {
positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
+ if (mSelectionActionMode != null) {
+ mSelectionActionMode.invalidate();
+ }
}
@Override
@@ -4472,7 +4475,7 @@ public class Editor {
private class CorrectionHighlighter {
private final Path mPath = new Path();
- private final Paint mPaint = new Paint();
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int mStart, mEnd;
private long mFadingStartTime;
private RectF mTempRectF;
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index ff587c2..f42959f 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -26,6 +26,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Typeface;
@@ -214,7 +215,7 @@ public class Switch extends CompoundButton {
public Switch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mTextPaint = new TextPaint();
+ mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
final Resources res = getResources();
mTextPaint.density = res.getDisplayMetrics().density;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 68c49cd..ee8e5c4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -238,6 +238,7 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
* @attr ref android.R.styleable#TextView_letterSpacing
* @attr ref android.R.styleable#TextView_fontFeatureSettings
* @attr ref android.R.styleable#TextView_breakStrategy
+ * @attr ref android.R.styleable#TextView_hyphenationFrequency
* @attr ref android.R.styleable#TextView_leftIndents
* @attr ref android.R.styleable#TextView_rightIndents
*/
@@ -555,6 +556,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private float mSpacingAdd = 0.0f;
private int mBreakStrategy;
+ private int mHyphenationFrequency;
private int[] mLeftIndents;
private int[] mRightIndents;
@@ -669,11 +671,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final Resources res = getResources();
final CompatibilityInfo compat = res.getCompatibilityInfo();
- mTextPaint = new TextPaint();
+ mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.density = res.getDisplayMetrics().density;
mTextPaint.setCompatibilityScaling(compat.applicationScale);
- mHighlightPaint = new Paint();
+ mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mHighlightPaint.setCompatibilityScaling(compat.applicationScale);
mMovement = getDefaultMovementMethod();
@@ -696,6 +698,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
float letterSpacing = 0;
String fontFeatureSettings = null;
mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
+ mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
final Resources.Theme theme = context.getTheme();
@@ -1154,6 +1157,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
break;
+ case com.android.internal.R.styleable.TextView_hyphenationFrequency:
+ mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE);
+ break;
+
case com.android.internal.R.styleable.TextView_leftIndents:
TypedArray margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID));
mLeftIndents = parseDimensionArray(margins);
@@ -3050,6 +3057,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets the hyphenation frequency. The default value for both TextView and EditText, which is set
+ * from the theme, is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}.
+ *
+ * @attr ref android.R.styleable#TextView_hyphenationFrequency
+ * @see #getHyphenationFrequency()
+ */
+ public void setHyphenationFrequency(@Layout.HyphenationFrequency int hyphenationFrequency) {
+ mHyphenationFrequency = hyphenationFrequency;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * @return the currently set hyphenation frequency.
+ *
+ * @attr ref android.R.styleable#TextView_hyphenationFrequency
+ * @see #setHyphenationFrequency(int)
+ */
+ @Layout.HyphenationFrequency
+ public int getHyphenationFrequency() {
+ return mHyphenationFrequency;
+ }
+
+ /**
* Set indents. Arguments are arrays holding an indent amount, one per line, measured in
* pixels. For lines past the last element in the array, the last element repeats.
*
@@ -6637,7 +6671,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setTextDir(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
- .setBreakStrategy(mBreakStrategy);
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency);
if (mLeftIndents != null || mRightIndents != null) {
builder.setIndents(mLeftIndents, mRightIndents);
}
@@ -6678,7 +6713,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Layout result = null;
if (mText instanceof Spannable) {
result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
- alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
+ alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad,
+ mBreakStrategy, mHyphenationFrequency,
getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
@@ -6726,7 +6762,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setTextDir(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
- .setBreakStrategy(mBreakStrategy);
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency);
if (mLeftIndents != null || mRightIndents != null) {
builder.setIndents(mLeftIndents, mRightIndents);
}