summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/Activity.java14
-rw-r--r--core/java/android/app/ActivityManager.java24
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java31
-rw-r--r--core/java/android/app/DatePickerDialog.java3
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java2
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java1
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/KeyguardManager.java9
-rw-r--r--core/java/android/app/Notification.java57
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java14
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/backup/BackupHelper.java7
-rw-r--r--core/java/android/app/usage/UsageEvents.java4
-rw-r--r--core/java/android/app/usage/UsageStats.java16
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java10
-rw-r--r--core/java/android/content/ContentResolver.java12
-rw-r--r--core/java/android/content/pm/PackageInstaller.java2
-rw-r--r--core/java/android/content/pm/PackageManager.java9
-rw-r--r--core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl4
-rw-r--r--core/java/android/hardware/camera2/TotalCaptureResult.java24
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java18
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java195
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java50
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java8
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java4
-rw-r--r--core/java/android/hardware/hdmi/HdmiPortInfo.java2
-rw-r--r--core/java/android/net/NetworkAgent.java8
-rw-r--r--core/java/android/net/NetworkBoundURLFactory.java35
-rw-r--r--core/java/android/net/NetworkFactory.java6
-rw-r--r--core/java/android/os/FileBridge.java7
-rw-r--r--core/java/android/os/PowerManager.java5
-rw-r--r--core/java/android/provider/CallLog.java12
-rw-r--r--core/java/android/provider/DocumentsContract.java4
-rw-r--r--core/java/android/provider/DocumentsProvider.java9
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl3
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java202
-rw-r--r--core/java/android/service/trust/TrustAgentService.java2
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java111
-rw-r--r--core/java/android/text/StaticLayout.java10
-rw-r--r--core/java/android/text/format/TimeFormatter.java137
-rw-r--r--core/java/android/transition/Transition.java4
-rw-r--r--core/java/android/util/Size.java37
-rw-r--r--core/java/android/util/SizeF.java37
-rw-r--r--core/java/android/view/HardwareRenderer.java2
-rw-r--r--core/java/android/view/RenderNode.java21
-rw-r--r--core/java/android/view/RenderNodeAnimator.java96
-rw-r--r--core/java/android/view/ThreadedRenderer.java24
-rw-r--r--core/java/android/view/View.java11
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java36
-rw-r--r--core/java/android/view/Window.java10
-rw-r--r--core/java/android/webkit/PermissionRequest.java6
-rw-r--r--core/java/android/webkit/WebChromeClient.java19
-rw-r--r--core/java/android/webkit/WebView.java16
-rw-r--r--core/java/android/widget/ActionMenuPresenter.java19
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java84
-rw-r--r--core/java/android/widget/Editor.java2
-rw-r--r--core/java/android/widget/ListPopupWindow.java14
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java2
-rw-r--r--core/java/android/widget/Spinner.java23
-rw-r--r--core/java/android/widget/Toolbar.java36
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java4
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java49
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java14
67 files changed, 1195 insertions, 466 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c80eeb9..2503d17 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5459,7 +5459,7 @@ public class Activity extends ContextThemeWrapper
* this method anytime before a return from {@link #onPause()}. If this call is successful
* then the activity will remain visible when {@link #onPause()} is called, and can continue to
* play media in the background, but it must stop playing and release resources prior to or
- * within the call to {@link #onVisibleBehindCancelled()}. If this call returns false, the
+ * within the call to {@link #onVisibleBehindCanceled()}. If this call returns false, the
* activity will not be visible in the background, and must release any media resources
* immediately.
*
@@ -5475,10 +5475,10 @@ public class Activity extends ContextThemeWrapper
* @return the resulting visibiity state. If true the activity may remain visible beyond
* {@link #onPause()}. If false then the activity may not count on being visible behind
* other translucent activities, and must stop any media playback and release resources.
- * Returning false may occur in lieu of a call to onVisibleBehindCancelled() so the return
+ * Returning false may occur in lieu of a call to onVisibleBehindCanceled() so the return
* value must be checked.
*
- * @see #onVisibleBehindCancelled()
+ * @see #onVisibleBehindCanceled()
* @see #onBackgroundVisibleBehindChanged(boolean)
*/
public boolean requestVisibleBehind(boolean visible) {
@@ -5498,7 +5498,7 @@ public class Activity extends ContextThemeWrapper
/**
* Called when a translucent activity over this activity is becoming opaque or another
* activity is being launched. Activities that override this method must call
- * <code>super.onVisibleBehindCancelled()</code> or a SuperNotCalledException will be thrown.
+ * <code>super.onVisibleBehindCanceled()</code> or a SuperNotCalledException will be thrown.
*
* <p>When this method is called the activity has 500 msec to release any resources it may be
* using while visible in the background.
@@ -5509,7 +5509,7 @@ public class Activity extends ContextThemeWrapper
* @see #requestVisibleBehind(boolean)
* @see #onBackgroundVisibleBehindChanged(boolean)
*/
- public void onVisibleBehindCancelled() {
+ public void onVisibleBehindCanceled() {
mCalled = true;
}
@@ -5521,7 +5521,7 @@ public class Activity extends ContextThemeWrapper
* {@link #requestVisibleBehind(boolean)}, false otherwise.
*
* @see #requestVisibleBehind(boolean)
- * @see #onVisibleBehindCancelled()
+ * @see #onVisibleBehindCanceled()
* @see #onBackgroundVisibleBehindChanged(boolean)
* @hide
*/
@@ -5544,7 +5544,7 @@ public class Activity extends ContextThemeWrapper
* @param visible true if a background activity is visible, false otherwise.
*
* @see #requestVisibleBehind(boolean)
- * @see #onVisibleBehindCancelled()
+ * @see #onVisibleBehindCanceled()
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ffb9c95..bc54055 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -52,6 +52,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
+import android.util.Size;
import android.util.Slog;
import java.io.FileDescriptor;
@@ -1026,24 +1027,13 @@ public class ActivityManager {
}
/**
- * Return the current design width for {@link AppTask} thumbnails, for use
+ * Return the current design dimensions for {@link AppTask} thumbnails, for use
* with {@link #addAppTask}.
*/
- public int getAppTaskThumbnailWidth() {
+ public Size getAppTaskThumbnailSize() {
synchronized (this) {
ensureAppTaskThumbnailSizeLocked();
- return mAppTaskThumbnailSize.x;
- }
- }
-
- /**
- * Return the current design height for {@link AppTask} thumbnails, for use
- * with {@link #addAppTask}.
- */
- public int getAppTaskThumbnailHeight() {
- synchronized (this) {
- ensureAppTaskThumbnailSizeLocked();
- return mAppTaskThumbnailSize.y;
+ return new Size(mAppTaskThumbnailSize.x, mAppTaskThumbnailSize.y);
}
}
@@ -1072,9 +1062,9 @@ public class ActivityManager {
* set on it.
* @param description Optional additional description information.
* @param thumbnail Thumbnail to use for the recents entry. Should be the size given by
- * {@link #getAppTaskThumbnailWidth()} and {@link #getAppTaskThumbnailHeight()}. If the
- * bitmap is not that exact size, it will be recreated in your process, probably in a way
- * you don't like, before the recents entry is added.
+ * {@link #getAppTaskThumbnailSize()}. If the bitmap is not that exact size, it will be
+ * recreated in your process, probably in a way you don't like, before the recents entry
+ * is added.
*
* @return Returns the task id of the newly added app task, or -1 if the add failed. The
* most likely cause of failure is that there is no more room for more tasks for your app.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d70e5df..38999a8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2485,11 +2485,11 @@ public final class ActivityThread {
final Activity activity = r.activity;
if (activity.mVisibleBehind) {
activity.mCalled = false;
- activity.onVisibleBehindCancelled();
+ activity.onVisibleBehindCanceled();
// Tick, tick, tick. The activity has 500 msec to return or it will be destroyed.
if (!activity.mCalled) {
throw new SuperNotCalledException("Activity " + activity.getLocalClassName() +
- " did not call through to super.onVisibleBehindCancelled()");
+ " did not call through to super.onVisibleBehindCanceled()");
}
activity.mVisibleBehind = false;
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index e4f2b88..a09a2e7 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -217,7 +217,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
}
protected void viewsReady(ArrayMap<String, View> sharedElements) {
- setSharedElements(sharedElements);
+ sharedElements.retainAll(mAllSharedElementNames);
+ mListener.remapSharedElements(mAllSharedElementNames, sharedElements);
+ mSharedElementNames.addAll(sharedElements.keySet());
+ mSharedElements.addAll(sharedElements.values());
if (getViewsTransition() != null) {
getDecor().captureTransitioningViews(mTransitioningViews);
mTransitioningViews.removeAll(mSharedElements);
@@ -339,32 +342,16 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
protected ArrayMap<String, View> mapSharedElements(ArrayList<String> accepted,
ArrayList<View> localViews) {
ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
- if (!mAllSharedElementNames.isEmpty()) {
- if (accepted != null) {
- for (int i = 0; i < accepted.size(); i++) {
- sharedElements.put(accepted.get(i), localViews.get(i));
- }
- } else {
- getDecor().findNamedViews(sharedElements);
+ if (accepted != null) {
+ for (int i = 0; i < accepted.size(); i++) {
+ sharedElements.put(accepted.get(i), localViews.get(i));
}
+ } else {
+ getDecor().findNamedViews(sharedElements);
}
return sharedElements;
}
- private void setSharedElements(ArrayMap<String, View> sharedElements) {
- sharedElements.retainAll(mAllSharedElementNames);
- mListener.remapSharedElements(mAllSharedElementNames, sharedElements);
- sharedElements.retainAll(mAllSharedElementNames);
- for (int i = 0; i < mAllSharedElementNames.size(); i++) {
- String name = mAllSharedElementNames.get(i);
- View sharedElement = sharedElements.get(name);
- if (sharedElement != null) {
- mSharedElementNames.add(name);
- mSharedElements.add(sharedElement);
- }
- }
- }
-
protected void setResultReceiver(ResultReceiver resultReceiver) {
mResultReceiver = resultReceiver;
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 1e556d6..f79d32b 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -135,6 +135,9 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
}
break;
+ case BUTTON_NEGATIVE:
+ cancel();
+ break;
}
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 75ecbd9..5a6898d 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -327,7 +327,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
public void run() {
if (mAnimations++ < MIN_ANIMATION_FRAMES) {
getDecor().postOnAnimation(this);
- } else {
+ } else if (mResultReceiver != null) {
mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
mResultReceiver = null; // all done sending messages.
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 43b9ea8..f31800d 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -174,6 +174,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
});
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
+ mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots);
TransitionManager.beginDelayedTransition(getDecor(), transition);
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 07e9a94..fb28c5d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -58,9 +58,12 @@ interface INotificationManager
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
- ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+ ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
+ void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
+ int getInterruptionFilterFromListener(in INotificationListener token);
+ void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
ComponentName getEffectsSuppressor();
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 50e3a10..e055237 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -56,6 +56,13 @@ public class KeyguardManager {
public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
/**
+ * @removed
+ */
+ public Intent getConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
+ return createConfirmDeviceCredentialIntent(title, description);
+ }
+
+ /**
* Get an intent to prompt the user to confirm credentials (pin, pattern or password)
* for the current user of the device. The caller is expected to launch this activity using
* {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
@@ -63,7 +70,7 @@ public class KeyguardManager {
*
* @return the intent for launching the activity or null if no password is required.
**/
- public Intent getConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
+ public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
if (!isKeyguardSecure()) return null;
Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
intent.putExtra(EXTRA_TITLE, title);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e1dc8bf..966d2ce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1424,6 +1424,8 @@ public class Notification implements Parcelable
extras.remove(Notification.EXTRA_LARGE_ICON);
extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
extras.remove(Notification.EXTRA_PICTURE);
+ // Prevent light notifications from being rebuilt.
+ extras.remove(Builder.EXTRA_NEEDS_REBUILD);
}
}
@@ -1868,6 +1870,15 @@ public class Notification implements Parcelable
private Notification mRebuildNotification = null;
/**
+ * Whether the build notification has three lines. This is used to make the top padding for
+ * both the contracted and expanded layout consistent.
+ *
+ * <p>
+ * This field is only valid during the build phase.
+ */
+ private boolean mHasThreeLines;
+
+ /**
* Constructs a new Builder with the defaults:
*
@@ -2564,19 +2575,23 @@ public class Notification implements Parcelable
return this;
}
- private Bitmap getProfileBadge() {
+ private Drawable getProfileBadgeDrawable() {
// Note: This assumes that the current user can read the profile badge of the
// originating user.
UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- Drawable badge = userManager.getBadgeForUser(new UserHandle(mOriginatingUserId), 0);
+ return userManager.getBadgeForUser(new UserHandle(mOriginatingUserId), 0);
+ }
+
+ private Bitmap getProfileBadge() {
+ Drawable badge = getProfileBadgeDrawable();
if (badge == null) {
return null;
}
- final int width = badge.getIntrinsicWidth();
- final int height = badge.getIntrinsicHeight();
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final int size = mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_badge_size);
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
- badge.setBounds(0, 0, width, height);
+ badge.setBounds(0, 0, size, size);
badge.draw(canvas);
return bitmap;
}
@@ -2602,6 +2617,12 @@ public class Notification implements Parcelable
return false;
}
+ private void shrinkLine3Text(RemoteViews contentView) {
+ float subTextSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_subtext_size);
+ contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
+ }
+
private RemoteViews applyStandardTemplate(int resId) {
RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(),
mOriginatingUserId, resId);
@@ -2674,10 +2695,7 @@ public class Notification implements Parcelable
if (showLine2) {
// need to shrink all the type to make sure everything fits
- final Resources res = mContext.getResources();
- final float subTextSize = res.getDimensionPixelSize(
- R.dimen.notification_subtext_size);
- contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
+ shrinkLine3Text(contentView);
}
if (mWhen != 0 && mShowWhen) {
@@ -2696,7 +2714,7 @@ public class Notification implements Parcelable
// Adjust padding depending on line count and font size.
contentView.setViewPadding(R.id.line1, 0, calculateTopPadding(mContext,
- hasThreeLines(), mContext.getResources().getConfiguration().fontScale),
+ mHasThreeLines, mContext.getResources().getConfiguration().fontScale),
0, 0);
// We want to add badge to first line of text.
@@ -2721,7 +2739,12 @@ public class Notification implements Parcelable
* is going to have one or two lines
*/
private boolean hasThreeLines() {
- boolean hasLine3 = mContentText != null || mContentInfo != null || mNumber > 0;
+ boolean contentTextInLine2 = mSubText != null && mContentText != null;
+
+ // If we have content text in line 2, badge goes into line 2, or line 3 otherwise
+ boolean badgeInLine3 = getProfileBadgeDrawable() != null && !contentTextInLine2;
+ boolean hasLine3 = mContentText != null || mContentInfo != null || mNumber > 0
+ || badgeInLine3;
boolean hasLine2 = (mSubText != null && mContentText != null) ||
(mSubText == null && (mProgressMax != 0 || mProgressIndeterminate));
return hasLine2 && hasLine3;
@@ -3092,6 +3115,7 @@ public class Notification implements Parcelable
if (mRebuildNotification == null) {
throw new IllegalStateException("rebuild() only valid when in 'rebuild' mode.");
}
+ mHasThreeLines = hasThreeLines();
Bundle extras = mRebuildNotification.extras;
@@ -3124,6 +3148,7 @@ public class Notification implements Parcelable
}
extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW);
+ mHasThreeLines = false;
return mRebuildNotification;
}
@@ -3238,6 +3263,7 @@ public class Notification implements Parcelable
*/
public Notification build() {
mOriginatingUserId = mContext.getUserId();
+ mHasThreeLines = hasThreeLines();
Notification n = buildUnstyled();
@@ -3259,6 +3285,7 @@ public class Notification implements Parcelable
mStyle.addExtras(n.extras);
}
+ mHasThreeLines = false;
return n;
}
@@ -3388,7 +3415,7 @@ public class Notification implements Parcelable
*/
protected void applyTopPadding(RemoteViews contentView) {
int topPadding = Builder.calculateTopPadding(mBuilder.mContext,
- mBuilder.hasThreeLines(),
+ mBuilder.mHasThreeLines,
mBuilder.mContext.getResources().getConfiguration().fontScale);
contentView.setViewPadding(R.id.line1, 0, topPadding, 0, 0);
}
@@ -3661,6 +3688,8 @@ public class Notification implements Parcelable
applyTopPadding(contentView);
+ mBuilder.shrinkLine3Text(contentView);
+
mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
return contentView;
@@ -3800,6 +3829,8 @@ public class Notification implements Parcelable
applyTopPadding(contentView);
+ mBuilder.shrinkLine3Text(contentView);
+
mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
return contentView;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 26c72a5..69b1139 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2456,10 +2456,10 @@ public class DevicePolicyManager {
* @throws IllegalArgumentException if the userId is invalid.
*/
@SystemApi
- public String getProfileOwnerNameAsUser(UserHandle user) throws IllegalArgumentException {
+ public String getProfileOwnerNameAsUser(int userId) throws IllegalArgumentException {
if (mService != null) {
try {
- return mService.getProfileOwnerName(user.getIdentifier());
+ return mService.getProfileOwnerName(userId);
} catch (RemoteException re) {
Log.w(TAG, "Failed to get profile owner");
throw new IllegalArgumentException(
@@ -2562,6 +2562,7 @@ public class DevicePolicyManager {
* @param agent Which component to enable features for.
* @param features List of features to enable. Consult specific TrustAgent documentation for
* the feature list.
+ * @hide
*/
public void setTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent,
List<String> features) {
@@ -2582,6 +2583,7 @@ public class DevicePolicyManager {
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param agent Which component to get enabled features for.
* @return List of enabled features.
+ * @hide
*/
public List<String> getTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent) {
if (mService != null) {
@@ -2689,10 +2691,10 @@ public class DevicePolicyManager {
* Called by a profile or device owner to set the permitted accessibility services. When
* set by a device owner or profile owner the restriction applies to all profiles of the
* user the device owner or profile owner is an admin for.
- *
+ *
* By default the user can use any accessiblity service. When zero or more packages have
* been added, accessiblity services that are not in the list and not part of the system
- * can not be enabled by the user.
+ * can not be enabled by the user.
*
* <p> Calling with a null value for the list disables the restriction so that all services
* can be used, calling with an empty list only allows the builtin system's services.
@@ -3325,10 +3327,10 @@ public class DevicePolicyManager {
* @param packageName package to check.
* @return true if the user shouldn't be able to uninstall the package.
*/
- public boolean getUninstallBlocked(ComponentName admin, String packageName) {
+ public boolean isUninstallBlocked(ComponentName admin, String packageName) {
if (mService != null) {
try {
- return mService.getUninstallBlocked(admin, packageName);
+ return mService.isUninstallBlocked(admin, packageName);
} catch (RemoteException re) {
Log.w(TAG, "Failed to call block uninstall on device policy service");
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 23f36fb..c984cf9 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -174,7 +174,7 @@ interface IDevicePolicyManager {
void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userId);
void setUninstallBlocked(in ComponentName admin, in String packageName, boolean uninstallBlocked);
- boolean getUninstallBlocked(in ComponentName admin, in String packageName);
+ boolean isUninstallBlocked(in ComponentName admin, in String packageName);
void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled);
boolean getCrossProfileCallerIdDisabled(in ComponentName who);
diff --git a/core/java/android/app/backup/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java
index e3f0d54..7cbbbc3 100644
--- a/core/java/android/app/backup/BackupHelper.java
+++ b/core/java/android/app/backup/BackupHelper.java
@@ -37,10 +37,9 @@ import android.os.ParcelFileDescriptor;
*/
public interface BackupHelper {
/**
- * Based on <code>oldState</code>, determine which of the files from the
- * application's data directory need to be backed up, write them to
- * <code>data</code>, and fill in <code>newState</code> with the state as it
- * exists now.
+ * Based on <code>oldState</code>, determine what application content
+ * needs to be backed up, write it to <code>data</code>, and fill in
+ * <code>newState</code> with the complete state as it exists now.
* <p>
* Implementing this method is much like implementing
* {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 2431ad0..fb80de2 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -106,7 +106,9 @@ public final class UsageEvents implements Parcelable {
}
/**
- * The time at which this event occurred.
+ * The time at which this event occurred, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getTimeStamp() {
return mTimeStamp;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index e47a802..abfc435 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -81,28 +81,36 @@ public final class UsageStats implements Parcelable {
}
/**
- * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents.
+ * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getFirstTimeStamp() {
return mBeginTimeStamp;
}
/**
- * Get the end of the time range this {@link android.app.usage.UsageStats} represents.
+ * Get the end of the time range this {@link android.app.usage.UsageStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getLastTimeStamp() {
return mEndTimeStamp;
}
/**
- * Get the last time this package was used.
+ * Get the last time this package was used, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getLastTimeUsed() {
return mLastTimeUsed;
}
/**
- * Get the total time this package spent in the foreground.
+ * Get the total time this package spent in the foreground, measured in milliseconds.
*/
public long getTotalTimeInForeground() {
return mTotalTimeInForeground;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index f9b8928..5830fcf 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -23,6 +23,7 @@ import android.util.ArrayMap;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* Provides access to device usage history and statistics. Usage data is aggregated into
@@ -149,7 +150,6 @@ public final class UsageStatsManager {
* @param endTime The exclusive end of the range of events to include in the results.
* @return A {@link UsageEvents}.
*/
- @SuppressWarnings("unchecked")
public UsageEvents queryEvents(long beginTime, long endTime) {
try {
UsageEvents iter = mService.queryEvents(beginTime, endTime,
@@ -170,15 +170,13 @@ public final class UsageStatsManager {
*
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
- * @return An {@link android.util.ArrayMap} keyed by package name or null if no stats are
+ * @return A {@link java.util.Map} keyed by package name, or null if no stats are
* available.
*/
- public ArrayMap<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
+ public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
if (stats.isEmpty()) {
- @SuppressWarnings("unchecked")
- ArrayMap<String, UsageStats> emptyStats = ArrayMap.EMPTY;
- return emptyStats;
+ return Collections.emptyMap();
}
ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b13792b..b2b48e8 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -27,6 +27,7 @@ import android.database.ContentObserver;
import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.database.IContentObserver;
+import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -161,6 +162,17 @@ public abstract class ContentResolver {
public static final String SCHEME_FILE = "file";
/**
+ * An extra {@link Point} describing the optimal size for a requested image
+ * resource, in pixels. If a provider has multiple sizes of the image, it
+ * should return the image closest to this size.
+ *
+ * @see #openTypedAssetFileDescriptor(Uri, String, Bundle)
+ * @see #openTypedAssetFileDescriptor(Uri, String, Bundle,
+ * CancellationSignal)
+ */
+ public static final String EXTRA_SIZE = "android.content.extra.SIZE";
+
+ /**
* This is the Android platform's base MIME type for a content: URI
* containing a Cursor of a single item. Applications should use this
* as the base type along with their own sub-type of their content: URIs
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index c928a18..44e24b1 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -623,7 +623,7 @@ public class PackageInstaller {
try {
final ParcelFileDescriptor clientSocket = mSession.openWrite(name,
offsetBytes, lengthBytes);
- return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor());
+ return new FileBridge.FileBridgeOutputStream(clientSocket);
} catch (RuntimeException e) {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5492775..fa2bb4d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1456,6 +1456,15 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports live TV and can display
+ * contents from TV inputs implemented with the
+ * {@link android.media.tv.TvInputService} API.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_LIVE_TV = "android.software.live_tv";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index caabed3..ca0935c 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -26,8 +26,8 @@ interface ICameraDeviceCallbacks
* Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
*/
- oneway void onCameraError(int errorCode, in CaptureResultExtras resultExtras);
- oneway void onCameraIdle();
+ oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
+ oneway void onDeviceIdle();
oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
oneway void onResultReceived(in CameraMetadataNative result,
in CaptureResultExtras resultExtras);
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index ec4bc7d..0895fe3 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -19,6 +19,7 @@ package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -48,13 +49,23 @@ import java.util.List;
*/
public final class TotalCaptureResult extends CaptureResult {
+ private final List<CaptureResult> mPartialResults;
+
/**
- * Takes ownership of the passed-in properties object
+ * Takes ownership of the passed-in camera metadata and the partial results
+ *
+ * @param partials a list of partial results; {@code null} will be substituted for an empty list
* @hide
*/
public TotalCaptureResult(CameraMetadataNative results, CaptureRequest parent,
- CaptureResultExtras extras) {
+ CaptureResultExtras extras, List<CaptureResult> partials) {
super(results, parent, extras);
+
+ if (partials == null) {
+ mPartialResults = new ArrayList<>();
+ } else {
+ mPartialResults = partials;
+ }
}
/**
@@ -65,6 +76,8 @@ public final class TotalCaptureResult extends CaptureResult {
*/
public TotalCaptureResult(CameraMetadataNative results, int sequenceId) {
super(results, sequenceId);
+
+ mPartialResults = new ArrayList<>();
}
/**
@@ -73,14 +86,13 @@ public final class TotalCaptureResult extends CaptureResult {
* <p>The list is returned is unmodifiable; attempting to modify it will result in a
* {@code UnsupportedOperationException} being thrown.</p>
*
- * <p>The list size will be inclusive between {@code 1} and
- * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}, in ascending order
+ * <p>The list size will be inclusive between {@code 0} and
+ * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}, with elements in ascending order
* of when {@link CameraCaptureSession.CaptureListener#onCaptureProgressed} was invoked.</p>
*
* @return unmodifiable list of partial results
*/
public List<CaptureResult> getPartialResults() {
- // TODO
- return Collections.unmodifiableList(null);
+ return Collections.unmodifiableList(mPartialResults);
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 621968b..9ca1fba 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -74,7 +74,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
private boolean mSkipUnconfigure = false;
/** Is the session in the process of aborting? Pay attention to BUSY->IDLE transitions. */
- private boolean mAborting;
+ private volatile boolean mAborting;
/**
* Create a new CameraCaptureSession.
@@ -346,6 +346,20 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
}
/**
+ * Whether currently in mid-abort.
+ *
+ * <p>This is used by the implementation to set the capture failure
+ * reason, in lieu of more accurate error codes from the camera service.
+ * Unsynchronized to avoid deadlocks between simultaneous session->device,
+ * device->session calls.</p>
+ *
+ * <p>Package-private.</p>
+ */
+ boolean isAborting() {
+ return mAborting;
+ }
+
+ /**
* Post calls into a CameraCaptureSession.StateListener to the user-specified {@code handler}.
*/
private StateListener createUserStateListenerProxy(Handler handler, StateListener listener) {
@@ -502,8 +516,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
// TODO: Queue captures during abort instead of failing them
// since the app won't be able to distinguish the two actives
+ // Don't signal the application since there's no clean mapping here
Log.w(TAG, "Device is now busy; do not submit new captures (TODO: allow this)");
- mStateListener.onActive(session);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 79ce9df..f5666bf 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -41,6 +41,7 @@ import android.view.Surface;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -384,7 +385,7 @@ public class CameraDeviceImpl extends CameraDevice {
catch (IllegalArgumentException e) {
// OK. camera service can reject stream config if it's not supported by HAL
// This is only the result of a programmer misusing the camera2 api.
- Log.e(TAG, "Stream configuration failed", e);
+ Log.w(TAG, "Stream configuration failed");
return false;
}
@@ -721,6 +722,13 @@ public class CameraDeviceImpl extends CameraDevice {
checkIfCameraClosedOrInError();
mDeviceHandler.post(mCallOnBusy);
+
+ // If already idle, just do a busy->idle transition immediately, don't actually
+ // flush.
+ if (mIdle) {
+ mDeviceHandler.post(mCallOnIdle);
+ return;
+ }
try {
LongParcelable lastFrameNumberRef = new LongParcelable();
mRemoteDevice.flush(/*out*/lastFrameNumberRef);
@@ -960,6 +968,8 @@ public class CameraDeviceImpl extends CameraDevice {
private long mCompletedFrameNumber = -1;
private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
+ /** Map frame numbers to list of partial results */
+ private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
private void update() {
Iterator<Long> iter = mFutureErrorSet.iterator();
@@ -976,8 +986,8 @@ public class CameraDeviceImpl extends CameraDevice {
/**
* This function is called every time when a result or an error is received.
- * @param frameNumber: the frame number corresponding to the result or error
- * @param isError: true if it is an error, false if it is not an error
+ * @param frameNumber the frame number corresponding to the result or error
+ * @param isError true if it is an error, false if it is not an error
*/
public void updateTracker(long frameNumber, boolean isError) {
if (isError) {
@@ -999,6 +1009,55 @@ public class CameraDeviceImpl extends CameraDevice {
update();
}
+ /**
+ * This function is called every time a result has been completed.
+ *
+ * <p>It keeps a track of all the partial results already created for a particular
+ * frame number.</p>
+ *
+ * @param frameNumber the frame number corresponding to the result
+ * @param result the total or partial result
+ * @param partial {@true} if the result is partial, {@code false} if total
+ */
+ public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
+
+ if (!partial) {
+ // Update the total result's frame status as being successful
+ updateTracker(frameNumber, /*isError*/false);
+ // Don't keep a list of total results, we don't need to track them
+ return;
+ }
+
+ if (result == null) {
+ // Do not record blank results; this also means there will be no total result
+ // so it doesn't matter that the partials were not recorded
+ return;
+ }
+
+ // Partial results must be aggregated in-order for that frame number
+ List<CaptureResult> partials = mPartialResults.get(frameNumber);
+ if (partials == null) {
+ partials = new ArrayList<>();
+ mPartialResults.put(frameNumber, partials);
+ }
+
+ partials.add(result);
+ }
+
+ /**
+ * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}.
+ *
+ * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker}
+ * is called again with new partials for that frame number).</p>
+ *
+ * @param frameNumber the frame number corresponding to the result
+ * @return a list of partial results for that frame with at least 1 element,
+ * or {@code null} if there were no partials recorded for that frame
+ */
+ public List<CaptureResult> popPartialResults(long frameNumber) {
+ return mPartialResults.remove(frameNumber);
+ }
+
public long getCompletedFrameNumber() {
return mCompletedFrameNumber;
}
@@ -1097,31 +1156,51 @@ public class CameraDeviceImpl extends CameraDevice {
*/
static final int ERROR_CAMERA_SERVICE = 2;
+ /**
+ * Camera has encountered an error processing a single request.
+ */
+ static final int ERROR_CAMERA_REQUEST = 3;
+
+ /**
+ * Camera has encountered an error producing metadata for a single capture
+ */
+ static final int ERROR_CAMERA_RESULT = 4;
+
+ /**
+ * Camera has encountered an error producing an image buffer for a single capture
+ */
+ static final int ERROR_CAMERA_BUFFER = 5;
+
@Override
public IBinder asBinder() {
return this;
}
@Override
- public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) {
- Runnable r = null;
+ public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "Device error received, code %d, frame number %d, request ID %d, subseq ID %d",
+ errorCode, resultExtras.getFrameNumber(), resultExtras.getRequestId(),
+ resultExtras.getSubsequenceId()));
+ }
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) {
return; // Camera already closed
}
- mInError = true;
switch (errorCode) {
case ERROR_CAMERA_DISCONNECTED:
- r = mCallOnDisconnected;
+ CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
break;
default:
Log.e(TAG, "Unknown error from camera device: " + errorCode);
// no break
case ERROR_CAMERA_DEVICE:
case ERROR_CAMERA_SERVICE:
- r = new Runnable() {
+ mInError = true;
+ Runnable r = new Runnable() {
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()) {
@@ -1129,21 +1208,19 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
};
+ CameraDeviceImpl.this.mDeviceHandler.post(r);
+ break;
+ case ERROR_CAMERA_REQUEST:
+ case ERROR_CAMERA_RESULT:
+ case ERROR_CAMERA_BUFFER:
+ onCaptureErrorLocked(errorCode, resultExtras);
break;
}
- CameraDeviceImpl.this.mDeviceHandler.post(r);
-
- // Fire onCaptureSequenceCompleted
- if (DEBUG) {
- Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
- }
- mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
- checkAndFireSequenceComplete();
}
}
@Override
- public void onCameraIdle() {
+ public void onDeviceIdle() {
if (DEBUG) {
Log.d(TAG, "Camera now idle");
}
@@ -1219,12 +1296,6 @@ public class CameraDeviceImpl extends CameraDevice {
boolean isPartialResult =
(resultExtras.getPartialResultCount() < mTotalPartialCount);
- // Update tracker (increment counter) when it's not a partial result.
- if (!isPartialResult) {
- mFrameNumberTracker.updateTracker(frameNumber,
- /*error*/false);
- }
-
// Check if we have a listener for this
if (holder == null) {
if (DEBUG) {
@@ -1232,6 +1303,9 @@ public class CameraDeviceImpl extends CameraDevice {
"holder is null, early return at frame "
+ frameNumber);
}
+
+ mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
+
return;
}
@@ -1241,14 +1315,17 @@ public class CameraDeviceImpl extends CameraDevice {
"camera is closed, early return at frame "
+ frameNumber);
}
+
+ mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
return;
}
final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
-
Runnable resultDispatch = null;
+ CaptureResult finalResult;
+
// Either send a partial result or the final capture completed result
if (isPartialResult) {
final CaptureResult resultAsCapture =
@@ -1266,9 +1343,14 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
};
+
+ finalResult = resultAsCapture;
} else {
+ List<CaptureResult> partialResults =
+ mFrameNumberTracker.popPartialResults(frameNumber);
+
final TotalCaptureResult resultAsCapture =
- new TotalCaptureResult(result, request, resultExtras);
+ new TotalCaptureResult(result, request, resultExtras, partialResults);
// Final capture result
resultDispatch = new Runnable() {
@@ -1282,19 +1364,80 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
};
+
+ finalResult = resultAsCapture;
}
holder.getHandler().post(resultDispatch);
+ // Collect the partials for a total result; or mark the frame as totally completed
+ mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
+
// Fire onCaptureSequenceCompleted
if (!isPartialResult) {
checkAndFireSequenceComplete();
}
+ }
+ }
+
+ /**
+ * Called by onDeviceError for handling single-capture failures.
+ */
+ private void onCaptureErrorLocked(int errorCode, CaptureResultExtras resultExtras) {
+
+ final int requestId = resultExtras.getRequestId();
+ final int subsequenceId = resultExtras.getSubsequenceId();
+ final long frameNumber = resultExtras.getFrameNumber();
+ final CaptureListenerHolder holder =
+ CameraDeviceImpl.this.mCaptureListenerMap.get(requestId);
+
+ final CaptureRequest request = holder.getRequest(subsequenceId);
+
+ // No way to report buffer errors right now
+ if (errorCode == ERROR_CAMERA_BUFFER) {
+ Log.e(TAG, String.format("Lost output buffer reported for frame %d", frameNumber));
+ return;
+ }
+
+ boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
+
+ // This is only approximate - exact handling needs the camera service and HAL to
+ // disambiguate between request failures to due abort and due to real errors.
+ // For now, assume that if the session believes we're mid-abort, then the error
+ // is due to abort.
+ int reason = (mCurrentSession != null && mCurrentSession.isAborting()) ?
+ CaptureFailure.REASON_FLUSHED :
+ CaptureFailure.REASON_ERROR;
+
+ final CaptureFailure failure = new CaptureFailure(
+ request,
+ reason,
+ /*dropped*/ mayHaveBuffers,
+ requestId,
+ frameNumber);
+
+ Runnable failureDispatch = new Runnable() {
+ @Override
+ public void run() {
+ if (!CameraDeviceImpl.this.isClosed()){
+ holder.getListener().onCaptureFailed(
+ CameraDeviceImpl.this,
+ request,
+ failure);
+ }
+ }
+ };
+ holder.getHandler().post(failureDispatch);
+ // Fire onCaptureSequenceCompleted if appropriate
+ if (DEBUG) {
+ Log.v(TAG, String.format("got error frame %d", frameNumber));
}
+ mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
+ checkAndFireSequenceComplete();
}
- }
+ } // public class CameraDeviceCallbacks
/**
* Default handler management.
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index febb015..f47ce79 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -67,7 +67,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -655,6 +654,15 @@ public class CameraMetadataNative implements Parcelable {
private Face[] getFaces() {
Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
+ byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
+ Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
+ int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
+ int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
+
+ if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
+ return null;
+ }
+
if (faceDetectMode == null) {
Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
@@ -670,8 +678,6 @@ public class CameraMetadataNative implements Parcelable {
}
// Face scores and rectangles are required by SIMPLE and FULL mode.
- byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
- Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
if (faceScores == null || faceRectangles == null) {
Log.w(TAG, "Expect face scores and rectangles to be non-null");
return new Face[0];
@@ -683,8 +689,6 @@ public class CameraMetadataNative implements Parcelable {
// To be safe, make number of faces is the minimal of all face info metadata length.
int numFaces = Math.min(faceScores.length, faceRectangles.length);
// Face id and landmarks are only required by FULL mode.
- int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
- int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
if (faceIds == null || faceLandmarks == null) {
Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
@@ -755,22 +759,32 @@ public class CameraMetadataNative implements Parcelable {
private LensShadingMap getLensShadingMap() {
float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
+ Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
+
+ // Do not warn if lsmArray is null while s is not. This is valid.
if (lsmArray == null) {
- Log.w(TAG, "getLensShadingMap - Lens shading map was null.");
return null;
}
- Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
+
+ if (s == null) {
+ Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
+ return null;
+ }
+
LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
return map;
}
private Location getGpsLocation() {
String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
- Location l = new Location(translateProcessToLocationProvider(processingMethod));
-
double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
+ if (areValuesAllNull(processingMethod, coords, timeStamp)) {
+ return null;
+ }
+
+ Location l = new Location(translateProcessToLocationProvider(processingMethod));
if (timeStamp != null) {
l.setTime(timeStamp);
} else {
@@ -873,7 +887,13 @@ public class CameraMetadataNative implements Parcelable {
float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
+
+ if (areValuesAllNull(red, green, blue)) {
+ return null;
+ }
+
if (red == null || green == null || blue == null) {
+ Log.w(TAG, "getTonemapCurve - missing tone curve components");
return null;
}
TonemapCurve tc = new TonemapCurve(red, green, blue);
@@ -1208,6 +1228,18 @@ public class CameraMetadataNative implements Parcelable {
}
}
+ /** Check if input arguments are all {@code null}.
+ *
+ * @param objs Input arguments for null check
+ * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
+ */
+ private static boolean areValuesAllNull(Object... objs) {
+ for (Object o : objs) {
+ if (o != null) return false;
+ }
+ return true;
+ }
+
static {
/*
* We use a class initializer to allow the native code to cache some field offsets
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 5cbf109..410934e 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -211,7 +211,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
- public void onCameraError(final int errorCode, final CaptureResultExtras resultExtras) {
+ public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
Message msg = getHandler().obtainMessage(CAMERA_ERROR,
/*arg1*/ errorCode, /*arg2*/ 0,
/*obj*/ resultExtras);
@@ -219,7 +219,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
- public void onCameraIdle() {
+ public void onDeviceIdle() {
Message msg = getHandler().obtainMessage(CAMERA_IDLE);
getHandler().sendMessage(msg);
}
@@ -267,11 +267,11 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
case CAMERA_ERROR: {
int errorCode = msg.arg1;
CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
- mCallbacks.onCameraError(errorCode, resultExtras);
+ mCallbacks.onDeviceError(errorCode, resultExtras);
break;
}
case CAMERA_IDLE:
- mCallbacks.onCameraIdle();
+ mCallbacks.onDeviceIdle();
break;
case CAPTURE_STARTED: {
long timestamp = msg.arg2 & 0xFFFFFFFFL;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 1cf7797..ffc55f1 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -97,7 +97,7 @@ public class LegacyCameraDevice implements AutoCloseable {
Log.d(TAG, "doing onError callback.");
}
try {
- mDeviceCallbacks.onCameraError(errorCode, extras);
+ mDeviceCallbacks.onDeviceError(errorCode, extras);
} catch (RemoteException e) {
throw new IllegalStateException(
"Received remote exception during onCameraError callback: ", e);
@@ -125,7 +125,7 @@ public class LegacyCameraDevice implements AutoCloseable {
Log.d(TAG, "doing onIdle callback.");
}
try {
- mDeviceCallbacks.onCameraIdle();
+ mDeviceCallbacks.onDeviceIdle();
} catch (RemoteException e) {
throw new IllegalStateException(
"Received remote exception during onCameraIdle callback: ", e);
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index 85e7531..2ec6126 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -166,7 +166,7 @@ public final class HdmiPortInfo implements Parcelable {
public String toString() {
StringBuffer s = new StringBuffer();
s.append("port_id: ").append(mId).append(", ");
- s.append("address: ").append(mAddress).append(", ");
+ s.append("address: ").append(String.format("0x%04x", mAddress)).append(", ");
s.append("cec: ").append(mCecSupported).append(", ");
s.append("arc: ").append(mArcSupported).append(", ");
s.append("mhl: ").append(mMhlSupported);
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 22da90e..8df9916 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -45,7 +45,7 @@ public abstract class NetworkAgent extends Handler {
private volatile AsyncChannel mAsyncChannel;
private final String LOG_TAG;
private static final boolean DBG = true;
- private static final boolean VDBG = true;
+ private static final boolean VDBG = false;
private final Context mContext;
private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
@@ -134,7 +134,7 @@ public abstract class NetworkAgent extends Handler {
throw new IllegalArgumentException();
}
- if (DBG) log("Registering NetworkAgent");
+ if (VDBG) log("Registering NetworkAgent");
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
@@ -148,7 +148,7 @@ public abstract class NetworkAgent extends Handler {
if (mAsyncChannel != null) {
log("Received new connection while already connected!");
} else {
- if (DBG) log("NetworkAgent fully connected");
+ if (VDBG) log("NetworkAgent fully connected");
AsyncChannel ac = new AsyncChannel();
ac.connected(null, this, msg.replyTo);
ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
@@ -164,7 +164,7 @@ public abstract class NetworkAgent extends Handler {
break;
}
case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
- if (DBG) log("CMD_CHANNEL_DISCONNECT");
+ if (VDBG) log("CMD_CHANNEL_DISCONNECT");
if (mAsyncChannel != null) mAsyncChannel.disconnect();
break;
}
diff --git a/core/java/android/net/NetworkBoundURLFactory.java b/core/java/android/net/NetworkBoundURLFactory.java
deleted file mode 100644
index 356100e..0000000
--- a/core/java/android/net/NetworkBoundURLFactory.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * An interface that describes a factory for network-specific {@link URL} objects.
- */
-public interface NetworkBoundURLFactory {
- /**
- * Returns a {@link URL} based on the given URL but bound to the specified {@code Network},
- * such that opening the URL will send all network traffic on the specified Network.
- *
- * @return a {@link URL} bound to this {@code Network}.
- * @throws MalformedURLException if the URL was not valid, or this factory cannot handle the
- * specified URL (e.g., if it does not support the protocol of the URL).
- */
- public URL getBoundURL(Network network, URL url) throws MalformedURLException;
-}
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index a20e8e7..6ddd8b3 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -46,6 +46,7 @@ import com.android.internal.util.Protocol;
**/
public class NetworkFactory extends Handler {
private static final boolean DBG = true;
+ private static final boolean VDBG = false;
private static final int BASE = Protocol.BASE_NETWORK_FACTORY;
/**
@@ -164,13 +165,14 @@ public class NetworkFactory extends Handler {
private void handleAddRequest(NetworkRequest request, int score) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
if (n == null) {
+ if (DBG) log("got request " + request + " with score " + score);
n = new NetworkRequestInfo(request, score);
mNetworkRequests.put(n.request.requestId, n);
} else {
+ if (VDBG) log("new score " + score + " for exisiting request " + request);
n.score = score;
}
- if (DBG) log("got request " + request + " with score " + score);
- if (DBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter);
+ if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter);
evalRequest(n);
}
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index bf8d15c..022a106 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -131,10 +131,17 @@ public class FileBridge extends Thread {
}
public static class FileBridgeOutputStream extends OutputStream {
+ private final ParcelFileDescriptor mClientPfd;
private final FileDescriptor mClient;
private final byte[] mTemp = new byte[MSG_LENGTH];
+ public FileBridgeOutputStream(ParcelFileDescriptor clientPfd) {
+ mClientPfd = clientPfd;
+ mClient = clientPfd.getFileDescriptor();
+ }
+
public FileBridgeOutputStream(FileDescriptor client) {
+ mClientPfd = null;
mClient = client;
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f7b0ead..00e2e22 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -248,7 +248,7 @@ public final class PowerManager {
* {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK} wake lock until the proximity sensor
* indicates that an object is not in close proximity.
*/
- public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
+ public static final int WAIT_FOR_DISTANT_PROXIMITY = 1;
/**
* Brightness value for fully on.
@@ -961,7 +961,8 @@ public final class PowerManager {
* </p>
*
* @param flags Combination of flag values to modify the release behavior.
- * Currently only {@link #WAIT_FOR_PROXIMITY_NEGATIVE} is supported.
+ * Currently only {@link #WAIT_FOR_DISTANT_PROXIMITY} is supported. Passing 0 is
+ * equivalent to calling {@link #release()}.
*/
public void release(int flags) {
synchronized (mToken) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 942da5a..0202f91 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -116,7 +116,8 @@ public class CallLog {
* </pre>
* </p>
*/
- public static final String EXTRA_CALL_TYPE_FILTER = "extra_call_type_filter";
+ public static final String EXTRA_CALL_TYPE_FILTER
+ = "android.provider.extra.call_type_filter";
/**
* Content uri used to access call log entries, including voicemail records. You must have
@@ -349,6 +350,15 @@ public class CallLog {
public static final String PHONE_ACCOUNT_ID = "subscription_id";
/**
+ * The identifier of a account that is unique to a specified component. Equivalent value
+ * to {@link #PHONE_ACCOUNT_ID}. For ContactsProvider internal use only.
+ * <P>Type: INTEGER</P>
+ *
+ * @hide
+ */
+ public static final String SUB_ID = "sub_id";
+
+ /**
* If a successful call is made that is longer than this duration, update the phone number
* in the ContactsProvider with the normalized version of the number, based on the user's
* current country code.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 327fe4a..9a0858a 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -511,8 +511,6 @@ public final class DocumentsContract {
public static final String METHOD_DELETE_DOCUMENT = "android:deleteDocument";
/** {@hide} */
- public static final String EXTRA_THUMBNAIL_SIZE = "thumbnail_size";
- /** {@hide} */
public static final String EXTRA_URI = "uri";
private static final String PATH_ROOT = "root";
@@ -819,7 +817,7 @@ public final class DocumentsContract {
ContentProviderClient client, Uri documentUri, Point size, CancellationSignal signal)
throws RemoteException, IOException {
final Bundle openOpts = new Bundle();
- openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size);
+ openOpts.putParcelable(ContentResolver.EXTRA_SIZE, size);
AssetFileDescriptor afd = null;
Bitmap bitmap = null;
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 021fff4..270d786 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -16,7 +16,6 @@
package android.provider;
-import static android.provider.DocumentsContract.EXTRA_THUMBNAIL_SIZE;
import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_RENAME_DOCUMENT;
@@ -763,8 +762,8 @@ public abstract class DocumentsProvider extends ContentProvider {
public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
throws FileNotFoundException {
enforceTree(uri);
- if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
- final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
+ if (opts != null && opts.containsKey(ContentResolver.EXTRA_SIZE)) {
+ final Point sizeHint = opts.getParcelable(ContentResolver.EXTRA_SIZE);
return openDocumentThumbnail(getDocumentId(uri), sizeHint, null);
} else {
return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
@@ -781,8 +780,8 @@ public abstract class DocumentsProvider extends ContentProvider {
Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
throws FileNotFoundException {
enforceTree(uri);
- if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
- final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
+ if (opts != null && opts.containsKey(ContentResolver.EXTRA_SIZE)) {
+ final Point sizeHint = opts.getParcelable(ContentResolver.EXTRA_SIZE);
return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal);
} else {
return super.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 95d1351..ae11f47 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2113,6 +2113,13 @@ public final class Settings {
public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
/**
+ * Microphone mute (int 1 = mute, 0 = not muted).
+ *
+ * @hide
+ */
+ public static final String MICROPHONE_MUTE = "microphone_mute";
+
+ /**
* Whether the notifications should use the ring volume (value of 1) or
* a separate notification volume (value of 0). In most cases, users
* will have this enabled so the notification and ringer volumes will be
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 93b2d3b..8ca9b6c 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -29,4 +29,5 @@ oneway interface INotificationListener
in NotificationRankingUpdate update);
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
void onListenerHintsChanged(int hints);
-} \ No newline at end of file
+ void onInterruptionFilterChanged(int interruptionFilter);
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 450b9a7..cb0bcf2 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -58,26 +58,55 @@ public abstract class NotificationListenerService extends Service {
private final String TAG = NotificationListenerService.class.getSimpleName()
+ "[" + getClass().getSimpleName() + "]";
- /** {@link #getCurrentListenerHints() Listener hints} constant - default state. */
- public static final int HINTS_NONE = 0;
-
- /** Bitmask range for {@link #getCurrentListenerHints() Listener hints} host interruption level
- * constants. */
- public static final int HOST_INTERRUPTION_LEVEL_MASK = 0x3;
-
- /** {@link #getCurrentListenerHints() Listener hints} constant - Normal interruption level. */
- public static final int HINT_HOST_INTERRUPTION_LEVEL_ALL = 1;
+ /**
+ * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
+ * Normal interruption filter.
+ */
+ public static final int INTERRUPTION_FILTER_ALL = 1;
- /** {@link #getCurrentListenerHints() Listener hints} constant - Priority interruption level. */
- public static final int HINT_HOST_INTERRUPTION_LEVEL_PRIORITY = 2;
+ /**
+ * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
+ * Priority interruption filter.
+ */
+ public static final int INTERRUPTION_FILTER_PRIORITY = 2;
- /** {@link #getCurrentListenerHints() Listener hints} constant - No interruptions level. */
- public static final int HINT_HOST_INTERRUPTION_LEVEL_NONE = 3;
+ /**
+ * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
+ * No interruptions filter.
+ */
+ public static final int INTERRUPTION_FILTER_NONE = 3;
/** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
* should disable notification sound, vibrating and other visual or aural effects.
- * This does not change the interruption level, only the effects. **/
- public static final int HINT_HOST_DISABLE_EFFECTS = 1 << 2;
+ * This does not change the interruption filter, only the effects. **/
+ public static final int HINT_HOST_DISABLE_EFFECTS = 1;
+
+ /**
+ * The full trim of the StatusBarNotification including all its features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_FULL = 0;
+
+ /**
+ * A light trim of the StatusBarNotification excluding the following features:
+ *
+ * <ol>
+ * <li>{@link Notification#tickerView tickerView}</li>
+ * <li>{@link Notification#contentView contentView}</li>
+ * <li>{@link Notification#largeIcon largeIcon}</li>
+ * <li>{@link Notification#bigContentView bigContentView}</li>
+ * <li>{@link Notification#headsUpContentView headsUpContentView}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li>
+ * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li>
+ * </ol>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_LIGHT = 1;
private INotificationListenerWrapper mWrapper = null;
private RankingMap mRankingMap;
@@ -197,6 +226,17 @@ public abstract class NotificationListenerService extends Service {
// optional
}
+ /**
+ * Implement this method to be notified when the
+ * {@link #getCurrentInterruptionFilter() interruption filter} changed.
+ *
+ * @param interruptionFilter The current
+ * {@link #getCurrentInterruptionFilter() interruption filter}.
+ */
+ public void onInterruptionFilterChanged(int interruptionFilter) {
+ // optional
+ }
+
private final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
@@ -301,13 +341,53 @@ public abstract class NotificationListenerService extends Service {
}
/**
+ * Sets the notification trim that will be received via {@link #onNotificationPosted}.
+ *
+ * <p>
+ * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the
+ * full notification features right away to reduce their memory footprint. Full notifications
+ * can be requested on-demand via {@link #getActiveNotifications(int)}.
+ *
+ * <p>
+ * Set to {@link #TRIM_FULL} initially.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}.
+ * See <code>TRIM_*</code> constants.
+ */
+ @SystemApi
+ public final void setOnNotificationPostedTrim(int trim) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim);
+ } catch (RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Request the list of outstanding notifications (that is, those that are visible to the
* current user). Useful when you don't know what's already been posted.
*
* @return An array of active notifications, sorted in natural order.
*/
public StatusBarNotification[] getActiveNotifications() {
- return getActiveNotifications(null);
+ return getActiveNotifications(null, TRIM_FULL);
+ }
+
+ /**
+ * Request the list of outstanding notifications (that is, those that are visible to the
+ * current user). Useful when you don't know what's already been posted.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of active notifications, sorted in natural order.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(int trim) {
+ return getActiveNotifications(null, trim);
}
/**
@@ -315,14 +395,33 @@ public abstract class NotificationListenerService extends Service {
* notifications but didn't want to retain the bits, and now need to go back and extract
* more data out of those notifications.
*
+ * @param keys the keys of the notifications to request
* @return An array of notifications corresponding to the requested keys, in the
* same order as the key list.
*/
public StatusBarNotification[] getActiveNotifications(String[] keys) {
- if (!isBound()) return null;
+ return getActiveNotifications(keys, TRIM_FULL);
+ }
+
+ /**
+ * Request one or more notifications by key. Useful if you have been keeping track of
+ * notifications but didn't want to retain the bits, and now need to go back and extract
+ * more data out of those notifications.
+ *
+ * @hide
+ *
+ * @param keys the keys of the notifications to request
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of notifications corresponding to the requested keys, in the
+ * same order as the key list.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) {
+ if (!isBound())
+ return null;
try {
- ParceledListSlice<StatusBarNotification> parceledList =
- getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
+ ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
+ .getActiveNotificationsFromListener(mWrapper, keys, trim);
List<StatusBarNotification> list = parceledList.getList();
int N = list.size();
@@ -345,15 +444,42 @@ public abstract class NotificationListenerService extends Service {
* shared across all listeners or a feature the notification host does not support or refuses
* to grant.
*
- * @return One or more of the HINT_ constants.
+ * @return Zero or more of the HINT_ constants.
*/
public final int getCurrentListenerHints() {
- if (!isBound()) return HINTS_NONE;
+ if (!isBound()) return 0;
try {
return getNotificationInterface().getHintsFromListener(mWrapper);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
- return HINTS_NONE;
+ return 0;
+ }
+ }
+
+ /**
+ * Gets the current notification interruption filter active on the host.
+ *
+ * <p>
+ * The interruption filter defines which notifications are allowed to interrupt the user
+ * (e.g. via sound &amp; vibration) and is applied globally. Listeners can find out whether
+ * a specific notification matched the interruption filter via
+ * {@link Ranking#matchesInterruptionFilter()}.
+ * <p>
+ * The current filter may differ from the previously requested filter if the notification host
+ * does not support or refuses to apply the requested filter, or if another component changed
+ * the filter in the meantime.
+ * <p>
+ * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
+ *
+ * @return One of the INTERRUPTION_FILTER_ constants, or 0 on errors.
+ */
+ public final int getCurrentInterruptionFilter() {
+ if (!isBound()) return 0;
+ try {
+ return getNotificationInterface().getHintsFromListener(mWrapper);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ return 0;
}
}
@@ -361,7 +487,7 @@ public abstract class NotificationListenerService extends Service {
* Sets the desired {@link #getCurrentListenerHints() listener hints}.
*
* <p>
- * This is merely a request, the host may or not choose to take action depending
+ * This is merely a request, the host may or may not choose to take action depending
* on other listener requests or other global state.
* <p>
* Listen for updates using {@link #onListenerHintsChanged(int)}.
@@ -378,6 +504,27 @@ public abstract class NotificationListenerService extends Service {
}
/**
+ * Sets the desired {@link #getCurrentInterruptionFilter() interruption filter}.
+ *
+ * <p>
+ * This is merely a request, the host may or may not choose to apply the requested
+ * interruption filter depending on other listener requests or other global state.
+ * <p>
+ * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
+ *
+ * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants.
+ */
+ public final void requestInterruptionFilter(int interruptionFilter) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface()
+ .requestInterruptionFilterFromListener(mWrapper, interruptionFilter);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Returns current ranking information.
*
* <p>
@@ -514,6 +661,15 @@ public abstract class NotificationListenerService extends Service {
Log.w(TAG, "Error running onListenerHintsChanged", t);
}
}
+
+ @Override
+ public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException {
+ try {
+ NotificationListenerService.this.onInterruptionFilterChanged(interruptionFilter);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onInterruptionFilterChanged", t);
+ }
+ }
}
private void applyUpdate(NotificationRankingUpdate update) {
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 337ae60..3ef5b37 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -89,6 +89,7 @@ public class TrustAgentService extends Service {
/**
* A white list of features that the given trust agent should support when otherwise disabled
* by device policy.
+ * @hide
*/
public static final String KEY_FEATURES = "trust_agent_features";
@@ -184,6 +185,7 @@ public class TrustAgentService extends Service {
*
* @param options Option feature bundle.
* @return true if the {@link TrustAgentService} supports this feature.
+ * @hide
*/
public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
return false;
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 2095773..519bc28 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -19,6 +19,7 @@ package android.service.voice;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Activity;
import android.content.Intent;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
@@ -84,20 +85,31 @@ public class AlwaysOnHotwordDetector {
private static final int STATE_NOT_READY = 0;
// Keyphrase management actions. Used in getManageIntent() ----//
- /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
MANAGE_ACTION_ENROLL,
MANAGE_ACTION_RE_ENROLL,
MANAGE_ACTION_UN_ENROLL
})
- public @interface ManageActions {}
+ private @interface ManageActions {}
- /** Indicates that we need to enroll. */
+ /**
+ * Indicates that we need to enroll.
+ *
+ * @hide
+ */
public static final int MANAGE_ACTION_ENROLL = 0;
- /** Indicates that we need to re-enroll. */
+ /**
+ * Indicates that we need to re-enroll.
+ *
+ * @hide
+ */
public static final int MANAGE_ACTION_RE_ENROLL = 1;
- /** Indicates that we need to un-enroll. */
+ /**
+ * Indicates that we need to un-enroll.
+ *
+ * @hide
+ */
public static final int MANAGE_ACTION_UN_ENROLL = 2;
//-- Flags for startRecognition ----//
@@ -111,7 +123,11 @@ public class AlwaysOnHotwordDetector {
})
public @interface RecognitionFlags {}
- /** Empty flag for {@link #startRecognition(int)}. */
+ /**
+ * Empty flag for {@link #startRecognition(int)}.
+ *
+ * @hide
+ */
public static final int RECOGNITION_FLAG_NONE = 0;
/**
* Recognition flag for {@link #startRecognition(int)} that indicates
@@ -264,7 +280,7 @@ public class AlwaysOnHotwordDetector {
/**
* Callbacks for always-on hotword detection.
*/
- public interface Callback {
+ public static abstract class Callback {
/**
* Called when the hotword availability changes.
* This indicates a change in the availability of recognition for the given keyphrase.
@@ -278,7 +294,7 @@ public class AlwaysOnHotwordDetector {
* @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNENROLLED
* @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_ENROLLED
*/
- void onAvailabilityChanged(int status);
+ public abstract void onAvailabilityChanged(int status);
/**
* Called when the keyphrase is spoken.
* This implicitly stops listening for the keyphrase once it's detected.
@@ -289,23 +305,23 @@ public class AlwaysOnHotwordDetector {
* This may contain the trigger audio, if requested when calling
* {@link AlwaysOnHotwordDetector#startRecognition(int)}.
*/
- void onDetected(@NonNull EventPayload eventPayload);
+ public abstract void onDetected(@NonNull EventPayload eventPayload);
/**
* Called when the detection fails due to an error.
*/
- void onError();
+ public abstract void onError();
/**
* Called when the recognition is paused temporarily for some reason.
* This is an informational callback, and the clients shouldn't be doing anything here
* except showing an indication on their UI if they have to.
*/
- void onRecognitionPaused();
+ public abstract void onRecognitionPaused();
/**
* Called when the recognition is resumed after it was temporarily paused.
* This is an informational callback, and the clients shouldn't be doing anything here
* except showing an indication on their UI if they have to.
*/
- void onRecognitionResumed();
+ public abstract void onRecognitionResumed();
}
/**
@@ -372,10 +388,10 @@ public class AlwaysOnHotwordDetector {
/**
* Starts recognition for the associated keyphrase.
*
+ * @see #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
+ * @see #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ *
* @param recognitionFlags The flags to control the recognition properties.
- * The allowed flags are {@link #RECOGNITION_FLAG_NONE},
- * {@link #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO} and
- * {@link #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS}.
* @return Indicates whether the call succeeded or not.
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
@@ -430,12 +446,34 @@ public class AlwaysOnHotwordDetector {
}
/**
- * Gets an intent to manage the associated keyphrase.
+ * Creates an intent to start the enrollment for the associated keyphrase.
+ * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+ * Starting re-enrollment is only valid if the keyphrase is un-enrolled,
+ * i.e. {@link #STATE_KEYPHRASE_UNENROLLED},
+ * otherwise {@link #createIntentToReEnroll()} should be preferred.
+ *
+ * @return An {@link Intent} to start enrollment for the given keyphrase.
+ * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
+ * Callers should only call this method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * @throws IllegalStateException if the detector is in an invalid state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
+ */
+ public Intent createIntentToEnroll() {
+ if (DBG) Slog.d(TAG, "createIntentToEnroll");
+ synchronized (mLock) {
+ return getManageIntentLocked(MANAGE_ACTION_ENROLL);
+ }
+ }
+
+ /**
+ * Creates an intent to start the un-enrollment for the associated keyphrase.
+ * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+ * Starting re-enrollment is only valid if the keyphrase is already enrolled,
+ * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
*
- * @param action The manage action that needs to be performed.
- * One of {@link #MANAGE_ACTION_ENROLL}, {@link #MANAGE_ACTION_RE_ENROLL} or
- * {@link #MANAGE_ACTION_UN_ENROLL}.
- * @return An {@link Intent} to manage the given keyphrase.
+ * @return An {@link Intent} to start un-enrollment for the given keyphrase.
* @throws UnsupportedOperationException if managing they keyphrase isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
@@ -443,10 +481,31 @@ public class AlwaysOnHotwordDetector {
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
- public Intent getManageIntent(@ManageActions int action) {
- if (DBG) Slog.d(TAG, "getManageIntent(" + action + ")");
+ public Intent createIntentToUnEnroll() {
+ if (DBG) Slog.d(TAG, "createIntentToUnEnroll");
synchronized (mLock) {
- return getManageIntentLocked(action);
+ return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL);
+ }
+ }
+
+ /**
+ * Creates an intent to start the re-enrollment for the associated keyphrase.
+ * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+ * Starting re-enrollment is only valid if the keyphrase is already enrolled,
+ * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
+ *
+ * @return An {@link Intent} to start re-enrollment for the given keyphrase.
+ * @throws UnsupportedOperationException if managing they keyphrase isn't supported.
+ * Callers should only call this method after a supported state callback on
+ * {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
+ * @throws IllegalStateException if the detector is in an invalid state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
+ */
+ public Intent createIntentToReEnroll() {
+ if (DBG) Slog.d(TAG, "createIntentToReEnroll");
+ synchronized (mLock) {
+ return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL);
}
}
@@ -462,12 +521,6 @@ public class AlwaysOnHotwordDetector {
"Managing the given keyphrase is not supported");
}
- if (action != MANAGE_ACTION_ENROLL
- && action != MANAGE_ACTION_RE_ENROLL
- && action != MANAGE_ACTION_UN_ENROLL) {
- throw new IllegalArgumentException("Invalid action specified " + action);
- }
-
return mKeyphraseEnrollmentInfo.getManageKeyphraseIntent(action, mText, mLocale);
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index aecf488..e82057c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -262,6 +262,8 @@ public class StaticLayout extends Layout {
int fit = paraStart;
float fitWidth = w;
int fitAscent = 0, fitDescent = 0, fitTop = 0, fitBottom = 0;
+ // same as fitWidth but not including any trailing whitespace
+ float fitWidthGraphing = w;
boolean hasTabOrEmoji = false;
boolean hasTab = false;
@@ -346,6 +348,9 @@ public class StaticLayout extends Layout {
if (w <= width || isSpaceOrTab) {
fitWidth = w;
+ if (!isSpaceOrTab) {
+ fitWidthGraphing = w;
+ }
fit = j + 1;
if (fmTop < fitTop)
@@ -365,7 +370,7 @@ public class StaticLayout extends Layout {
breakOpp[breakOppIndex] == j - paraStart + 1;
if (isLineBreak) {
- okWidth = w;
+ okWidth = fitWidthGraphing;
ok = j + 1;
if (fitTop < okTop)
@@ -426,6 +431,7 @@ public class StaticLayout extends Layout {
j = here - 1; // restart j-span loop from here, compensating for the j++
ok = fit = here;
w = 0;
+ fitWidthGraphing = w;
fitAscent = fitDescent = fitTop = fitBottom = 0;
okAscent = okDescent = okTop = okBottom = 0;
@@ -842,7 +848,7 @@ public class StaticLayout extends Layout {
void prepare() {
mMeasured = MeasuredText.obtain();
}
-
+
void finish() {
mMeasured = MeasuredText.recycle(mMeasured);
}
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index ec79b36..3a63805 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -22,8 +22,7 @@ package android.text.format;
import android.content.res.Resources;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
+import java.nio.CharBuffer;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
@@ -31,15 +30,13 @@ import libcore.icu.LocaleData;
import libcore.util.ZoneInfo;
/**
- * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. The
- * main issue with this implementation is the treatment of characters as ASCII, despite returning
- * localized (UTF-16) strings from the LocaleData.
+ * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java.
*
* <p>This class is not thread safe.
*/
class TimeFormatter {
- // An arbitrary value outside the range representable by a byte / ASCII character code.
- private static final int FORCE_LOWER_CASE = 0x100;
+ // An arbitrary value outside the range representable by a char.
+ private static final int FORCE_LOWER_CASE = -1;
private static final int SECSPERMIN = 60;
private static final int MINSPERHOUR = 60;
@@ -62,10 +59,9 @@ class TimeFormatter {
private final String dateTimeFormat;
private final String timeOnlyFormat;
private final String dateOnlyFormat;
- private final Locale locale;
private StringBuilder outputBuilder;
- private Formatter outputFormatter;
+ private Formatter numberFormatter;
public TimeFormatter() {
synchronized (TimeFormatter.class) {
@@ -84,7 +80,6 @@ class TimeFormatter {
this.dateTimeFormat = sDateTimeFormat;
this.timeOnlyFormat = sTimeOnlyFormat;
this.dateOnlyFormat = sDateOnlyFormat;
- this.locale = locale;
localeData = sLocaleData;
}
}
@@ -97,19 +92,21 @@ class TimeFormatter {
StringBuilder stringBuilder = new StringBuilder();
outputBuilder = stringBuilder;
- outputFormatter = new Formatter(stringBuilder, locale);
+ // This uses the US locale because number localization is handled separately (see below)
+ // and locale sensitive strings are output directly using outputBuilder.
+ numberFormatter = new Formatter(stringBuilder, Locale.US);
formatInternal(pattern, wallTime, zoneInfo);
String result = stringBuilder.toString();
// This behavior is the source of a bug since some formats are defined as being
- // in ASCII. Generally localization is very broken.
+ // in ASCII and not localized.
if (localeData.zeroDigit != '0') {
result = localizeDigits(result);
}
return result;
} finally {
outputBuilder = null;
- outputFormatter = null;
+ numberFormatter = null;
}
}
@@ -132,38 +129,30 @@ class TimeFormatter {
* {@link #outputBuilder}.
*/
private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
- // Convert to ASCII bytes to be compatible with old implementation behavior.
- byte[] bytes = pattern.getBytes(StandardCharsets.US_ASCII);
- if (bytes.length == 0) {
- return;
- }
-
- ByteBuffer formatBuffer = ByteBuffer.wrap(bytes);
+ CharBuffer formatBuffer = CharBuffer.wrap(pattern);
while (formatBuffer.remaining() > 0) {
- boolean outputCurrentByte = true;
- char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position()));
- if (currentByteAsChar == '%') {
- outputCurrentByte = handleToken(formatBuffer, wallTime, zoneInfo);
+ boolean outputCurrentChar = true;
+ char currentChar = formatBuffer.get(formatBuffer.position());
+ if (currentChar == '%') {
+ outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo);
}
- if (outputCurrentByte) {
- currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position()));
- outputBuilder.append(currentByteAsChar);
+ if (outputCurrentChar) {
+ outputBuilder.append(formatBuffer.get(formatBuffer.position()));
}
-
formatBuffer.position(formatBuffer.position() + 1);
}
}
- private boolean handleToken(ByteBuffer formatBuffer, ZoneInfo.WallTime wallTime,
+ private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime,
ZoneInfo zoneInfo) {
- // The byte at formatBuffer.position() is expected to be '%' at this point.
+ // The char at formatBuffer.position() is expected to be '%' at this point.
int modifier = 0;
while (formatBuffer.remaining() > 1) {
- // Increment the position then get the new current byte.
+ // Increment the position then get the new current char.
formatBuffer.position(formatBuffer.position() + 1);
- char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position()));
- switch (currentByteAsChar) {
+ char currentChar = formatBuffer.get(formatBuffer.position());
+ switch (currentChar) {
case 'A':
modifyAndAppend((wallTime.getWeekDay() < 0
|| wallTime.getWeekDay() >= DAYSPERWEEK)
@@ -206,7 +195,7 @@ class TimeFormatter {
formatInternal("%m/%d/%y", wallTime, zoneInfo);
return false;
case 'd':
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
wallTime.getMonthDay());
return false;
case 'E':
@@ -218,46 +207,46 @@ class TimeFormatter {
case '0':
case '^':
case '#':
- modifier = currentByteAsChar;
+ modifier = currentChar;
continue;
case 'e':
- outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
wallTime.getMonthDay());
return false;
case 'F':
formatInternal("%Y-%m-%d", wallTime, zoneInfo);
return false;
case 'H':
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
wallTime.getHour());
return false;
case 'I':
int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12;
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour);
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour);
return false;
case 'j':
int yearDay = wallTime.getYearDay() + 1;
- outputFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"),
+ numberFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"),
yearDay);
return false;
case 'k':
- outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
wallTime.getHour());
return false;
case 'l':
int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12;
- outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2);
+ numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2);
return false;
case 'M':
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
wallTime.getMinute());
return false;
case 'm':
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
wallTime.getMonth() + 1);
return false;
case 'n':
- modifyAndAppend("\n", modifier);
+ outputBuilder.append('\n');
return false;
case 'p':
modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
@@ -274,27 +263,27 @@ class TimeFormatter {
formatInternal("%I:%M:%S %p", wallTime, zoneInfo);
return false;
case 'S':
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
wallTime.getSecond());
return false;
case 's':
int timeInSeconds = wallTime.mktime(zoneInfo);
- modifyAndAppend(Integer.toString(timeInSeconds), modifier);
+ outputBuilder.append(Integer.toString(timeInSeconds));
return false;
case 'T':
formatInternal("%H:%M:%S", wallTime, zoneInfo);
return false;
case 't':
- modifyAndAppend("\t", modifier);
+ outputBuilder.append('\t');
return false;
case 'U':
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
(wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay())
/ DAYSPERWEEK);
return false;
case 'u':
int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay();
- outputFormatter.format("%d", day);
+ numberFormatter.format("%d", day);
return false;
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
@@ -326,9 +315,9 @@ class TimeFormatter {
--year;
yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
}
- if (currentByteAsChar == 'V') {
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w);
- } else if (currentByteAsChar == 'g') {
+ if (currentChar == 'V') {
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w);
+ } else if (currentChar == 'g') {
outputYear(year, false, true, modifier);
} else {
outputYear(year, true, true, modifier);
@@ -342,10 +331,10 @@ class TimeFormatter {
int n = (wallTime.getYearDay() + DAYSPERWEEK - (
wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1)
: (DAYSPERWEEK - 1))) / DAYSPERWEEK;
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
return false;
case 'w':
- outputFormatter.format("%d", wallTime.getWeekDay());
+ numberFormatter.format("%d", wallTime.getWeekDay());
return false;
case 'X':
formatInternal(timeOnlyFormat, wallTime, zoneInfo);
@@ -371,17 +360,17 @@ class TimeFormatter {
return false;
}
int diff = wallTime.getGmtOffset();
- String sign;
+ char sign;
if (diff < 0) {
- sign = "-";
+ sign = '-';
diff = -diff;
} else {
- sign = "+";
+ sign = '+';
}
- modifyAndAppend(sign, modifier);
+ outputBuilder.append(sign);
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR);
- outputFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff);
+ numberFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff);
return false;
}
case '+':
@@ -422,7 +411,6 @@ class TimeFormatter {
break;
default:
outputBuilder.append(str);
-
}
}
@@ -443,14 +431,14 @@ class TimeFormatter {
}
if (outputTop) {
if (lead == 0 && trail < 0) {
- modifyAndAppend("-0", modifier);
+ outputBuilder.append("-0");
} else {
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead);
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead);
}
}
if (outputBottom) {
int n = ((trail < 0) ? -trail : trail);
- outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
}
}
@@ -472,24 +460,24 @@ class TimeFormatter {
}
/**
- * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII in order to
- * be compatible with the old native implementation.
+ * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
*/
private static boolean brokenIsUpper(char toCheck) {
return toCheck >= 'A' && toCheck <= 'Z';
}
/**
- * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII in order to
- * be compatible with the old native implementation.
+ * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
*/
private static boolean brokenIsLower(char toCheck) {
return toCheck >= 'a' && toCheck <= 'z';
}
/**
- * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII in order to
- * be compatible with the old native implementation.
+ * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
*/
private static char brokenToLower(char input) {
if (input >= 'A' && input <= 'Z') {
@@ -499,8 +487,8 @@ class TimeFormatter {
}
/**
- * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII in order to
- * be compatible with the old native implementation.
+ * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
*/
private static char brokenToUpper(char input) {
if (input >= 'a' && input <= 'z') {
@@ -509,11 +497,4 @@ class TimeFormatter {
return input;
}
- /**
- * Safely convert a byte containing an ASCII character to a char, even for character codes
- * > 127.
- */
- private static char convertToChar(byte b) {
- return (char) (b & 0xFF);
- }
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 59ba71f..bd52e71 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1656,7 +1656,7 @@ public abstract class Transition implements Cloneable {
WindowId windowId = sceneRoot.getWindowId();
for (int i = numOldAnims - 1; i >= 0; i--) {
AnimationInfo info = runningAnimators.valueAt(i);
- if (info.view != null && windowId.equals(info.windowId)) {
+ if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
Animator anim = runningAnimators.keyAt(i);
anim.pause();
}
@@ -1689,7 +1689,7 @@ public abstract class Transition implements Cloneable {
WindowId windowId = sceneRoot.getWindowId();
for (int i = numOldAnims - 1; i >= 0; i--) {
AnimationInfo info = runningAnimators.valueAt(i);
- if (info.view != null && windowId.equals(info.windowId)) {
+ if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
Animator anim = runningAnimators.keyAt(i);
anim.resume();
}
diff --git a/core/java/android/util/Size.java b/core/java/android/util/Size.java
index d58f778..6424344 100644
--- a/core/java/android/util/Size.java
+++ b/core/java/android/util/Size.java
@@ -16,12 +16,15 @@
package android.util;
-import static com.android.internal.util.Preconditions.*;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.os.Parcel;
+import android.os.Parcelable;
/**
* Immutable class for describing width and height dimensions in pixels.
*/
-public final class Size {
+public final class Size implements Parcelable {
/**
* Create a new immutable Size instance.
*
@@ -33,6 +36,11 @@ public final class Size {
mHeight = height;
}
+ private Size(Parcel in) {
+ mWidth = in.readInt();
+ mHeight = in.readInt();
+ }
+
/**
* Get the width of the size (in pixels).
* @return width
@@ -147,6 +155,29 @@ public final class Size {
return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mWidth);
+ out.writeInt(mHeight);
+ }
+
+ public static final Parcelable.Creator<Size> CREATOR = new Parcelable.Creator<Size>() {
+ @Override
+ public Size createFromParcel(Parcel in) {
+ return new Size(in);
+ }
+
+ @Override
+ public Size[] newArray(int size) {
+ return new Size[size];
+ }
+ };
+
private final int mWidth;
private final int mHeight;
-};
+}
diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java
index 0a8b4ed..88bb439 100644
--- a/core/java/android/util/SizeF.java
+++ b/core/java/android/util/SizeF.java
@@ -16,7 +16,10 @@
package android.util;
-import static com.android.internal.util.Preconditions.*;
+import static com.android.internal.util.Preconditions.checkArgumentFinite;
+
+import android.os.Parcel;
+import android.os.Parcelable;
/**
* Immutable class for describing width and height dimensions in some arbitrary
@@ -25,7 +28,7 @@ import static com.android.internal.util.Preconditions.*;
* Width and height are finite values stored as a floating point representation.
* </p>
*/
-public final class SizeF {
+public final class SizeF implements Parcelable {
/**
* Create a new immutable SizeF instance.
*
@@ -43,6 +46,11 @@ public final class SizeF {
mHeight = checkArgumentFinite(height, "height");
}
+ private SizeF(Parcel in) {
+ mWidth = in.readFloat();
+ mHeight = in.readFloat();
+ }
+
/**
* Get the width of the size (as an arbitrary unit).
* @return width
@@ -103,6 +111,29 @@ public final class SizeF {
return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight);
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeFloat(mWidth);
+ out.writeFloat(mHeight);
+ }
+
+ public static final Parcelable.Creator<SizeF> CREATOR = new Parcelable.Creator<SizeF>() {
+ @Override
+ public SizeF createFromParcel(Parcel in) {
+ return new SizeF(in);
+ }
+
+ @Override
+ public SizeF[] newArray(int size) {
+ return new SizeF[size];
+ }
+ };
+
private final float mWidth;
private final float mHeight;
-};
+}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index de90899..edb3798 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -485,4 +485,6 @@ public abstract class HardwareRenderer {
* Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
*/
abstract void notifyFramePending();
+
+ abstract void registerAnimatingRenderNode(RenderNode animator);
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 099f153..9dc9766 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -167,10 +167,13 @@ public class RenderNode {
public static final int STATUS_DREW = 0x4;
private boolean mValid;
- private final long mNativeRenderNode;
+ // Do not access directly unless you are ThreadedRenderer
+ final long mNativeRenderNode;
+ private final View mOwningView;
- private RenderNode(String name) {
+ private RenderNode(String name, View owningView) {
mNativeRenderNode = nCreate(name);
+ mOwningView = owningView;
}
/**
@@ -178,6 +181,7 @@ public class RenderNode {
*/
private RenderNode(long nativePtr) {
mNativeRenderNode = nativePtr;
+ mOwningView = null;
}
/**
@@ -188,8 +192,8 @@ public class RenderNode {
*
* @return A new RenderNode.
*/
- public static RenderNode create(String name) {
- return new RenderNode(name);
+ public static RenderNode create(String name, @Nullable View owningView) {
+ return new RenderNode(name, owningView);
}
/**
@@ -805,7 +809,15 @@ public class RenderNode {
///////////////////////////////////////////////////////////////////////////
public void addAnimator(RenderNodeAnimator animator) {
+ if (mOwningView == null || mOwningView.mAttachInfo == null) {
+ throw new IllegalStateException("Cannot start this animator on a detached view!");
+ }
nAddAnimator(mNativeRenderNode, animator.getNativeAnimator());
+ mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
+ }
+
+ public void endAllAnimators() {
+ nEndAllAnimators(mNativeRenderNode);
}
///////////////////////////////////////////////////////////////////////////
@@ -891,6 +903,7 @@ public class RenderNode {
///////////////////////////////////////////////////////////////////////////
private static native void nAddAnimator(long renderNode, long animatorPtr);
+ private static native void nEndAllAnimators(long renderNode);
///////////////////////////////////////////////////////////////////////////
// Finalization
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 9433237..fa4a13a 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,7 +19,6 @@ package android.view;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.animation.Animator.AnimatorListener;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
@@ -30,7 +29,6 @@ import com.android.internal.view.animation.FallbackLUTInterpolator;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -89,8 +87,11 @@ public class RenderNodeAnimator extends Animator {
private float mFinalValue;
private TimeInterpolator mInterpolator;
- private boolean mStarted = false;
- private boolean mFinished = false;
+ private static final int STATE_PREPARE = 0;
+ private static final int STATE_DELAYED = 1;
+ private static final int STATE_RUNNING = 2;
+ private static final int STATE_FINISHED = 3;
+ private int mState = STATE_PREPARE;
private long mUnscaledDuration = 300;
private long mUnscaledStartDelay = 0;
@@ -111,13 +112,11 @@ public class RenderNodeAnimator extends Animator {
mRenderProperty = property;
mFinalValue = finalValue;
mUiThreadHandlesDelay = true;
- init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
- property, finalValue));
+ init(nCreateAnimator(property, finalValue));
}
public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
init(nCreateCanvasPropertyFloatAnimator(
- new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), finalValue));
mUiThreadHandlesDelay = false;
}
@@ -132,14 +131,12 @@ public class RenderNodeAnimator extends Animator {
*/
public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
init(nCreateCanvasPropertyPaintAnimator(
- new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), paintField, finalValue));
mUiThreadHandlesDelay = false;
}
public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
- init(nCreateRevealAnimator(new WeakReference<RenderNodeAnimator>(this),
- x, y, startRadius, endRadius));
+ init(nCreateRevealAnimator(x, y, startRadius, endRadius));
mUiThreadHandlesDelay = true;
}
@@ -148,7 +145,7 @@ public class RenderNodeAnimator extends Animator {
}
private void checkMutable() {
- if (mStarted) {
+ if (mState != STATE_PREPARE) {
throw new IllegalStateException("Animator has already started, cannot change it now!");
}
}
@@ -176,11 +173,11 @@ public class RenderNodeAnimator extends Animator {
throw new IllegalStateException("Missing target!");
}
- if (mStarted) {
+ if (mState != STATE_PREPARE) {
throw new IllegalStateException("Already started!");
}
- mStarted = true;
+ mState = STATE_DELAYED;
applyInterpolator();
if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
@@ -192,7 +189,8 @@ public class RenderNodeAnimator extends Animator {
}
private void doStart() {
- nStart(mNativePtr.get());
+ mState = STATE_RUNNING;
+ nStart(mNativePtr.get(), this);
// Alpha is a special snowflake that has the canonical value stored
// in mTransformationInfo instead of in RenderNode, so we need to update
@@ -203,11 +201,7 @@ public class RenderNodeAnimator extends Animator {
mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
}
- final ArrayList<AnimatorListener> listeners = cloneListeners();
- final int numListeners = listeners == null ? 0 : listeners.size();
- for (int i = 0; i < numListeners; i++) {
- listeners.get(i).onAnimationStart(this);
- }
+ notifyStartListeners();
if (mViewTarget != null) {
// Kick off a frame to start the process
@@ -215,10 +209,21 @@ public class RenderNodeAnimator extends Animator {
}
}
+ private void notifyStartListeners() {
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
+ final int numListeners = listeners == null ? 0 : listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onAnimationStart(this);
+ }
+ }
+
@Override
public void cancel() {
- if (!mFinished) {
- getHelper().removeDelayedAnimation(this);
+ if (mState != STATE_FINISHED) {
+ if (mState == STATE_DELAYED) {
+ getHelper().removeDelayedAnimation(this);
+ notifyStartListeners();
+ }
nEnd(mNativePtr.get());
final ArrayList<AnimatorListener> listeners = cloneListeners();
@@ -226,12 +231,17 @@ public class RenderNodeAnimator extends Animator {
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationCancel(this);
}
+
+ if (mViewTarget != null) {
+ // Kick off a frame to flush the state change
+ mViewTarget.invalidateViewProperty(true, false);
+ }
}
}
@Override
public void end() {
- if (!mFinished) {
+ if (mState != STATE_FINISHED) {
nEnd(mNativePtr.get());
}
}
@@ -248,24 +258,21 @@ public class RenderNodeAnimator extends Animator {
public void setTarget(View view) {
mViewTarget = view;
- mTarget = view.mRenderNode;
- mTarget.addAnimator(this);
+ setTarget(mViewTarget.mRenderNode);
}
public void setTarget(Canvas canvas) {
if (!(canvas instanceof GLES20RecordingCanvas)) {
throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
}
-
final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
setTarget(recordingCanvas.mNode);
}
- public void setTarget(RenderNode node) {
+ private void setTarget(RenderNode node) {
if (mTarget != null) {
throw new IllegalStateException("Target already set!");
}
- mViewTarget = null;
mTarget = node;
mTarget.addAnimator(this);
}
@@ -308,12 +315,12 @@ public class RenderNodeAnimator extends Animator {
@Override
public boolean isRunning() {
- return mStarted && !mFinished;
+ return mState == STATE_DELAYED || mState == STATE_RUNNING;
}
@Override
public boolean isStarted() {
- return mStarted;
+ return mState != STATE_PREPARE;
}
@Override
@@ -328,13 +335,23 @@ public class RenderNodeAnimator extends Animator {
}
protected void onFinished() {
- mFinished = true;
+ if (mState == STATE_DELAYED) {
+ getHelper().removeDelayedAnimation(this);
+ notifyStartListeners();
+ }
+ mState = STATE_FINISHED;
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationEnd(this);
}
+
+ // Release the native object, as it has a global reference to us. This
+ // breaks the cyclic reference chain, and allows this object to be
+ // GC'd
+ mNativePtr.release();
+ mNativePtr = null;
}
@SuppressWarnings("unchecked")
@@ -427,11 +444,8 @@ public class RenderNodeAnimator extends Animator {
}
// Called by native
- private static void callOnFinished(WeakReference<RenderNodeAnimator> weakThis) {
- RenderNodeAnimator animator = weakThis.get();
- if (animator != null) {
- animator.onFinished();
- }
+ private static void callOnFinished(RenderNodeAnimator animator) {
+ animator.onFinished();
}
@Override
@@ -439,22 +453,20 @@ public class RenderNodeAnimator extends Animator {
throw new IllegalStateException("Cannot clone this animator");
}
- private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
- int property, float finalValue);
- private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
+ private static native long nCreateAnimator(int property, float finalValue);
+ private static native long nCreateCanvasPropertyFloatAnimator(
long canvasProperty, float finalValue);
- private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
+ private static native long nCreateCanvasPropertyPaintAnimator(
long canvasProperty, int paintField, float finalValue);
- private static native long nCreateRevealAnimator(WeakReference<RenderNodeAnimator> weakThis,
+ private static native long nCreateRevealAnimator(
int x, int y, float startRadius, float endRadius);
private static native void nSetStartValue(long nativePtr, float startValue);
private static native void nSetDuration(long nativePtr, long duration);
private static native long nGetDuration(long nativePtr);
private static native void nSetStartDelay(long nativePtr, long startDelay);
- private static native long nGetStartDelay(long nativePtr);
private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
- private static native void nStart(long animPtr);
+ private static native void nStart(long animPtr, RenderNodeAnimator finishListener);
private static native void nEnd(long animPtr);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 3af214d..ca08ecc 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -277,7 +277,11 @@ public class ThreadedRenderer extends HardwareRenderer {
final int saveCount = canvas.save();
canvas.translate(mInsetLeft, mInsetTop);
callbacks.onHardwarePreDraw(canvas);
+
+ canvas.insertReorderBarrier();
canvas.drawRenderNode(view.getDisplayList());
+ canvas.insertInorderBarrier();
+
callbacks.onHardwarePostDraw(canvas);
canvas.restoreToCount(saveCount);
mRootNodeNeedsUpdate = false;
@@ -312,6 +316,20 @@ public class ThreadedRenderer extends HardwareRenderer {
attachInfo.mIgnoreDirtyState = false;
+ // register animating rendernodes which started animating prior to renderer
+ // creation, which is typical for animators started prior to first draw
+ if (attachInfo.mPendingAnimatingRenderNodes != null) {
+ final int count = attachInfo.mPendingAnimatingRenderNodes.size();
+ for (int i = 0; i < count; i++) {
+ registerAnimatingRenderNode(
+ attachInfo.mPendingAnimatingRenderNodes.get(i));
+ }
+ attachInfo.mPendingAnimatingRenderNodes.clear();
+ // We don't need this anymore as subsequent calls to
+ // ViewRootImpl#attachRenderNodeAnimator will go directly to us.
+ attachInfo.mPendingAnimatingRenderNodes = null;
+ }
+
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
recordDuration, view.getResources().getDisplayMetrics().density);
if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
@@ -370,6 +388,11 @@ public class ThreadedRenderer extends HardwareRenderer {
}
@Override
+ void registerAnimatingRenderNode(RenderNode animator) {
+ nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
+ }
+
+ @Override
protected void finalize() throws Throwable {
try {
nDeleteProxy(mNativeProxy);
@@ -466,6 +489,7 @@ public class ThreadedRenderer extends HardwareRenderer {
private static native int nSyncAndDrawFrame(long nativeProxy,
long frameTimeNanos, long recordDuration, float density);
private static native void nDestroyCanvasAndSurface(long nativeProxy);
+ private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2d58ecf..fce6f0b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3565,7 +3565,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
- mRenderNode = RenderNode.create(getClass().getName());
+ mRenderNode = RenderNode.create(getClass().getName(), this);
if (!sCompatibilityDone && context != null) {
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
@@ -4161,7 +4161,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
View() {
mResources = null;
- mRenderNode = RenderNode.create(getClass().getName());
+ mRenderNode = RenderNode.create(getClass().getName(), this);
}
private static SparseArray<String> getAttributeMap() {
@@ -15183,9 +15183,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param renderNode Existing RenderNode, or {@code null}
* @return A valid display list for the specified drawable
*/
- private static RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) {
+ private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) {
if (renderNode == null) {
- renderNode = RenderNode.create(drawable.getClass().getName());
+ renderNode = RenderNode.create(drawable.getClass().getName(), this);
}
final Rect bounds = drawable.getBounds();
@@ -19911,6 +19911,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mHardwareAccelerated;
boolean mHardwareAccelerationRequested;
HardwareRenderer mHardwareRenderer;
+ List<RenderNode> mPendingAnimatingRenderNodes;
/**
* The state of the display to which the window is attached, as reported
@@ -20691,6 +20692,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mPosted) {
return;
}
+
final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
final long minEventIntevalMillis =
ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
@@ -20699,7 +20701,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
run();
} else {
postDelayed(this, minEventIntevalMillis - timeSinceLastMillis);
- mPosted = true;
mPostedWithDelay = true;
}
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index bae0cfb..b73b9fa 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -430,6 +430,10 @@ public class ViewPropertyAnimator {
}
}
mPendingAnimations.clear();
+ mPendingSetupAction = null;
+ mPendingCleanupAction = null;
+ mPendingOnStartAction = null;
+ mPendingOnEndAction = null;
mView.removeCallbacks(mAnimationStarter);
if (mRTBackend != null) {
mRTBackend.cancelAll();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bb469a3..49d925f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -333,6 +333,8 @@ public final class ViewRootImpl implements ViewParent,
private boolean mRemoved;
private boolean mIsEmulator;
+ private boolean mIsCircularEmulator;
+ private final boolean mWindowIsRound;
/**
* Consistency verifier for debugging purposes.
@@ -388,6 +390,8 @@ public final class ViewRootImpl implements ViewParent,
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
+ mWindowIsRound = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound);
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -671,6 +675,17 @@ public final class ViewRootImpl implements ViewParent,
ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
}
+ public void registerAnimatingRenderNode(RenderNode animator) {
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.registerAnimatingRenderNode(animator);
+ } else {
+ if (mAttachInfo.mPendingAnimatingRenderNodes == null) {
+ mAttachInfo.mPendingAnimatingRenderNodes = new ArrayList<RenderNode>();
+ }
+ mAttachInfo.mPendingAnimatingRenderNodes.add(animator);
+ }
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -1183,14 +1198,7 @@ public final class ViewRootImpl implements ViewParent,
void dispatchApplyInsets(View host) {
mDispatchContentInsets.set(mAttachInfo.mContentInsets);
mDispatchStableInsets.set(mAttachInfo.mStableInsets);
- boolean isRound = false;
- if ((mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0
- && mDisplay.getDisplayId() == 0) {
- // we're fullscreen and not hosted in an ActivityView
- isRound = (mIsEmulator && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))
- || mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_windowIsRound);
- }
+ final boolean isRound = (mIsEmulator && mIsCircularEmulator) || mWindowIsRound;
host.dispatchApplyWindowInsets(new WindowInsets(
mDispatchContentInsets, null /* windowDecorInsets */,
mDispatchStableInsets, isRound));
@@ -2329,6 +2337,16 @@ public final class ViewRootImpl implements ViewParent,
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
+ // For whatever reason we didn't create a HardwareRenderer, end any
+ // hardware animations that are now dangling
+ if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
+ final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
+ for (int i = 0; i < count; i++) {
+ mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
+ }
+ mAttachInfo.mPendingAnimatingRenderNodes.clear();
+ }
+
if (mReportNextDraw) {
mReportNextDraw = false;
if (mAttachInfo.mHardwareRenderer != null) {
@@ -5431,6 +5449,8 @@ public final class ViewRootImpl implements ViewParent,
// detect emulator
mIsEmulator = Build.HARDWARE.contains("goldfish");
+ mIsCircularEmulator =
+ SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false);
}
});
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2c7ea3e..9b6f200 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1304,12 +1304,22 @@ public abstract class Window {
public abstract int getVolumeControlStream();
/**
+ * Sets a {@link MediaController} to send media keys and volume changes to.
+ * If set, this should be preferred for all media keys and volume requests
+ * sent to this window.
+ *
+ * @param controller The controller for the session which should receive
+ * media keys and volume changes.
* @see android.app.Activity#setMediaController(android.media.session.MediaController)
*/
public void setMediaController(MediaController controller) {
}
/**
+ * Gets the {@link MediaController} that was previously set.
+ *
+ * @return The controller which should receive events.
+ * @see #setMediaController(android.media.session.MediaController)
* @see android.app.Activity#getMediaController()
*/
public MediaController getMediaController() {
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 862e8c2..6ad639c 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -19,8 +19,10 @@ package android.webkit;
import android.net.Uri;
/**
- * This interface defines a permission request and is used when web content
- * requests access to protected resources.
+ * This class defines a permission request and is used when web content
+ * requests access to protected resources. The permission request related events
+ * are delivered via {@link WebChromeClient#onPermissionRequest} and
+ * {@link WebChromeClient#onPermissionRequestCanceled}.
*
* Either {@link #grant(String[]) grant()} or {@link #deny()} must be called in UI
* thread to respond to the request.
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 35c9598..547acfa 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -452,14 +452,16 @@ public class WebChromeClient {
*/
public static abstract class FileChooserParams {
/** Open single file. Requires that the file exists before allowing the user to pick it. */
- public static final int OPEN = 0;
+ public static final int MODE_OPEN = 0;
/** Like Open but allows multiple files to be selected. */
- public static final int OPEN_MULTIPLE = 1;
+ public static final int MODE_OPEN_MULTIPLE = 1;
/** Like Open but allows a folder to be selected. The implementation should enumerate
- all files selected by this operation. */
- public static final int OPEN_FOLDER = 2;
+ all files selected by this operation.
+ This feature is not supported at the moment.
+ @hide */
+ public static final int MODE_OPEN_FOLDER = 2;
/** Allows picking a nonexistent file and saving it. */
- public static final int SAVE = 3;
+ public static final int MODE_SAVE = 3;
/**
* Returns a helper to simplify choosing and uploading files. The helper builds a default
@@ -474,7 +476,8 @@ public class WebChromeClient {
public abstract int getMode();
/**
- * Returns an array of acceptable MIME types. The array will be empty if no
+ * Returns an array of acceptable MIME types. The returned MIME type
+ * could be partial such as audio/*. The array will be empty if no
* acceptable types are specified.
*/
public abstract String[] getAcceptTypes();
@@ -494,9 +497,9 @@ public class WebChromeClient {
public abstract CharSequence getTitle();
/**
- * The file path of a default selection if specified, or null.
+ * The file name of a default selection if specified, or null.
*/
- public abstract String getDefaultFilename();
+ public abstract String getFilenameHint();
};
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1b0cb3d..e1f19ee 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1624,10 +1624,18 @@ public class WebView extends AbsoluteLayout
}
/**
- * Enable drawing the entire HTML document at a significant performance
- * cost. Call this to enable drawing and capturing HTML content outside of
- * the WebView's viewport. This should be called before any WebViews are
- * created.
+ * For apps targeting the L release, WebView has a new default behavior that reduces
+ * memory footprint and increases performance by intelligently choosing
+ * the portion of the HTML document that needs to be drawn. These
+ * optimizations are transparent to the developers. However, under certain
+ * circumstances, an App developer may want to disable them:
+ * 1. When an app uses {@link #onDraw} to do own drawing and accesses portions
+ * of the page that is way outside the visible portion of the page.
+ * 2. When an app uses {@link #capturePicture} to capture a very large HTML document.
+ * Note that capturePicture is a deprecated API.
+ *
+ * Enabling drawing the entire HTML document has a significant performance
+ * cost. This method should be called before any WebViews are created.
*/
public static void enableSlowWholeDocumentDraw() {
getFactory().getStatics().enableSlowWholeDocumentDraw();
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 7123b9a..ef8c006 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -19,6 +19,8 @@ package android.widget;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseBooleanArray;
@@ -645,6 +647,23 @@ public class ActionMenuPresenter extends BaseMenuPresenter
super.onInitializeAccessibilityNodeInfo(info);
info.setCanOpenPopup(true);
}
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ // Set up the hotspot bounds to be centered on the image.
+ final Drawable d = getDrawable();
+ final Drawable bg = getBackground();
+ if (d != null && bg != null) {
+ final Rect bounds = d.getBounds();
+ final int height = bottom - top;
+ final int offset = (height - bounds.width()) / 2;
+ final int hotspotLeft = bounds.left - offset;
+ final int hotspotRight = bounds.right + offset;
+ bg.setHotspotBounds(hotspotLeft, 0, hotspotRight, height);
+ }
+ }
}
private class OverflowPopup extends MenuPopupHelper {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index eb232fd..3b16aba 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -35,9 +35,8 @@ import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-
import com.android.internal.R;
-
+import java.lang.ref.WeakReference;
/**
* <p>An editable text view that shows completion suggestions automatically
@@ -85,8 +84,8 @@ import com.android.internal.R;
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownHeight
- * @attr ref android.R.styleable#AutoCompleteTextView_dropDownVerticalOffset
- * @attr ref android.R.styleable#AutoCompleteTextView_dropDownHorizontalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
*/
public class AutoCompleteTextView extends EditText implements Filter.FilterListener {
static final boolean DEBUG = false;
@@ -130,7 +129,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
public AutoCompleteTextView(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.autoCompleteTextViewStyle);
+ this(context, attrs, R.attr.autoCompleteTextViewStyle);
}
public AutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -141,23 +140,17 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mPopup = new ListPopupWindow(context, attrs,
- com.android.internal.R.attr.autoCompleteTextViewStyle);
+ mPopup = new ListPopupWindow(context, attrs, defStyleAttr, defStyleRes);
mPopup.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
- final TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
- mThreshold = a.getInt(
- R.styleable.AutoCompleteTextView_completionThreshold, 2);
+ mThreshold = a.getInt(R.styleable.AutoCompleteTextView_completionThreshold, 2);
mPopup.setListSelector(a.getDrawable(R.styleable.AutoCompleteTextView_dropDownSelector));
- mPopup.setVerticalOffset((int)
- a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f));
- mPopup.setHorizontalOffset((int)
- a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f));
-
+
// Get the anchor's id now, but the view won't be ready, so wait to actually get the
// view and store it in mDropDownAnchorView lazily in getDropDownAnchorView later.
// Defaults to NO_ID, in which case the getDropDownAnchorView method will simply return
@@ -167,11 +160,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
// For dropdown width, the developer can specify a specific width, or MATCH_PARENT
// (for full screen width) or WRAP_CONTENT (to match the width of the anchored view).
- mPopup.setWidth(a.getLayoutDimension(
- R.styleable.AutoCompleteTextView_dropDownWidth,
+ mPopup.setWidth(a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownWidth,
ViewGroup.LayoutParams.WRAP_CONTENT));
- mPopup.setHeight(a.getLayoutDimension(
- R.styleable.AutoCompleteTextView_dropDownHeight,
+ mPopup.setHeight(a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownHeight,
ViewGroup.LayoutParams.WRAP_CONTENT));
mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView,
@@ -373,6 +364,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
*
* @param offset the vertical offset
+ *
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
*/
public void setDropDownVerticalOffset(int offset) {
mPopup.setVerticalOffset(offset);
@@ -382,6 +375,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
*
* @return the vertical offset
+ *
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
*/
public int getDropDownVerticalOffset() {
return mPopup.getVerticalOffset();
@@ -391,6 +386,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
*
* @param offset the horizontal offset
+ *
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
*/
public void setDropDownHorizontalOffset(int offset) {
mPopup.setHorizontalOffset(offset);
@@ -400,6 +397,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
*
* @return the horizontal offset
+ *
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
*/
public int getDropDownHorizontalOffset() {
return mPopup.getHorizontalOffset();
@@ -629,7 +628,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
*/
public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
if (mObserver == null) {
- mObserver = new PopupDataSetObserver();
+ mObserver = new PopupDataSetObserver(this);
} else if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
@@ -1255,25 +1254,44 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
}
- private class PopupDataSetObserver extends DataSetObserver {
+ /**
+ * Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView.
+ * <p>
+ * This way, if adapter has a longer life span than the View, we won't leak the View, instead
+ * we will just leak a small Observer with 1 field.
+ */
+ private static class PopupDataSetObserver extends DataSetObserver {
+ private final WeakReference<AutoCompleteTextView> mViewReference;
+
+ private PopupDataSetObserver(AutoCompleteTextView view) {
+ mViewReference = new WeakReference<AutoCompleteTextView>(view);
+ }
+
@Override
public void onChanged() {
- if (mAdapter != null) {
+ final AutoCompleteTextView textView = mViewReference.get();
+ if (textView != null && textView.mAdapter != null) {
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
// of iterating through the list of observers.
- post(new Runnable() {
- public void run() {
- final ListAdapter adapter = mAdapter;
- if (adapter != null) {
- // This will re-layout, thus resetting mDataChanged, so that the
- // listView click listener stays responsive
- updateDropDownForFilter(adapter.getCount());
- }
- }
- });
+ textView.post(updateRunnable);
}
}
+
+ private final Runnable updateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ final AutoCompleteTextView textView = mViewReference.get();
+ if (textView == null) {
+ return;
+ }
+ final ListAdapter adapter = textView.mAdapter;
+ if (adapter == null) {
+ return;
+ }
+ textView.updateDropDownForFilter(adapter.getCount());
+ }
+ };
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 29c8298..46b225d 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -147,7 +147,7 @@ public class Editor {
boolean isDirty;
public TextDisplayList(String name) {
isDirty = true;
- displayList = RenderNode.create(name);
+ displayList = RenderNode.create(name, null);
}
boolean needsRecord() { return isDirty || !displayList.isValid(); }
}
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 6a514ba..3c186e3 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -40,6 +41,7 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AccelerateDecelerateInterpolator;
+import com.android.internal.R;
import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
import java.util.Locale;
@@ -208,6 +210,18 @@ public class ListPopupWindow {
*/
public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mContext = context;
+
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ListPopupWindow,
+ defStyleAttr, defStyleRes);
+ mDropDownHorizontalOffset = a.getDimensionPixelOffset(
+ R.styleable.ListPopupWindow_dropDownHorizontalOffset, 0);
+ mDropDownVerticalOffset = a.getDimensionPixelOffset(
+ R.styleable.ListPopupWindow_dropDownVerticalOffset, 0);
+ if (mDropDownVerticalOffset != 0) {
+ mDropDownVerticalOffsetSet = true;
+ }
+ a.recycle();
+
mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
// Set the default layout direction to match the default locale one
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 602f955..56bdb9b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -176,7 +176,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
RemoteViewsAdapter adapter;
final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
if ((adapter = mAdapter.get()) != null) {
- mgr.unbindRemoteViewsService(context.getPackageName(), appWidgetId, intent);
+ mgr.unbindRemoteViewsService(context.getOpPackageName(), appWidgetId, intent);
} else {
Slog.w(TAG, "unbind: adapter was null");
}
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 9914800..98d52ff 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -49,14 +49,14 @@ import android.widget.PopupWindow.OnDismissListener;
*
* <p>See the <a href="{@docRoot}guide/topics/ui/controls/spinner.html">Spinners</a> guide.</p>
*
- * @attr ref android.R.styleable#Spinner_dropDownHorizontalOffset
* @attr ref android.R.styleable#Spinner_dropDownSelector
- * @attr ref android.R.styleable#Spinner_dropDownVerticalOffset
* @attr ref android.R.styleable#Spinner_dropDownWidth
* @attr ref android.R.styleable#Spinner_gravity
* @attr ref android.R.styleable#Spinner_popupBackground
* @attr ref android.R.styleable#Spinner_prompt
* @attr ref android.R.styleable#Spinner_spinnerMode
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
*/
@Widget
public class Spinner extends AbsSpinner implements OnClickListener {
@@ -209,17 +209,6 @@ public class Spinner extends AbsSpinner implements OnClickListener {
ViewGroup.LayoutParams.WRAP_CONTENT);
popup.setBackgroundDrawable(a.getDrawable(
com.android.internal.R.styleable.Spinner_popupBackground));
- final int verticalOffset = a.getDimensionPixelOffset(
- com.android.internal.R.styleable.Spinner_dropDownVerticalOffset, 0);
- if (verticalOffset != 0) {
- popup.setVerticalOffset(verticalOffset);
- }
-
- final int horizontalOffset = a.getDimensionPixelOffset(
- com.android.internal.R.styleable.Spinner_dropDownHorizontalOffset, 0);
- if (horizontalOffset != 0) {
- popup.setHorizontalOffset(horizontalOffset);
- }
mPopup = popup;
mForwardingListener = new ForwardingListener(this) {
@@ -303,7 +292,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
*
* @param pixels Vertical offset in pixels
*
- * @attr ref android.R.styleable#Spinner_dropDownVerticalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
*/
public void setDropDownVerticalOffset(int pixels) {
mPopup.setVerticalOffset(pixels);
@@ -315,7 +304,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
*
* @return Vertical offset in pixels
*
- * @attr ref android.R.styleable#Spinner_dropDownVerticalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
*/
public int getDropDownVerticalOffset() {
return mPopup.getVerticalOffset();
@@ -327,7 +316,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
*
* @param pixels Horizontal offset in pixels
*
- * @attr ref android.R.styleable#Spinner_dropDownHorizontalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
*/
public void setDropDownHorizontalOffset(int pixels) {
mPopup.setHorizontalOffset(pixels);
@@ -339,7 +328,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
*
* @return Horizontal offset in pixels
*
- * @attr ref android.R.styleable#Spinner_dropDownHorizontalOffset
+ * @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
*/
public int getDropDownHorizontalOffset() {
return mPopup.getHorizontalOffset();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 818efaa..ece8aa4 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -244,6 +244,16 @@ public class Toolbar extends ViewGroup {
// Set the default context, since setPopupTheme() may be a no-op.
mPopupContext = mContext;
setPopupTheme(a.getResourceId(R.styleable.Toolbar_popupTheme, 0));
+
+ final Drawable navIcon = a.getDrawable(R.styleable.Toolbar_navigationIcon);
+ if (navIcon != null) {
+ setNavigationIcon(navIcon);
+ final CharSequence navDesc = a.getText(
+ R.styleable.Toolbar_navigationContentDescription);
+ if (!TextUtils.isEmpty(navDesc)) {
+ setNavigationContentDescription(navDesc);
+ }
+ }
a.recycle();
}
@@ -669,6 +679,8 @@ public class Toolbar extends ViewGroup {
* as screen readers or tooltips.
*
* @return The navigation button's content description
+ *
+ * @attr ref android.R.styleable#Toolbar_navigationContentDescription
*/
@Nullable
public CharSequence getNavigationContentDescription() {
@@ -682,6 +694,8 @@ public class Toolbar extends ViewGroup {
*
* @param resId Resource ID of a content description string to set, or 0 to
* clear the description
+ *
+ * @attr ref android.R.styleable#Toolbar_navigationContentDescription
*/
public void setNavigationContentDescription(int resId) {
setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
@@ -694,6 +708,8 @@ public class Toolbar extends ViewGroup {
*
* @param description Content description to set, or <code>null</code> to
* clear the content description
+ *
+ * @attr ref android.R.styleable#Toolbar_navigationContentDescription
*/
public void setNavigationContentDescription(@Nullable CharSequence description) {
if (!TextUtils.isEmpty(description)) {
@@ -715,6 +731,8 @@ public class Toolbar extends ViewGroup {
* tooltips.</p>
*
* @param resId Resource ID of a drawable to set
+ *
+ * @attr ref android.R.styleable#Toolbar_navigationIcon
*/
public void setNavigationIcon(int resId) {
setNavigationIcon(getContext().getDrawable(resId));
@@ -731,6 +749,8 @@ public class Toolbar extends ViewGroup {
* tooltips.</p>
*
* @param icon Drawable to set, may be null to clear the icon
+ *
+ * @attr ref android.R.styleable#Toolbar_navigationIcon
*/
public void setNavigationIcon(@Nullable Drawable icon) {
if (icon != null) {
@@ -751,6 +771,8 @@ public class Toolbar extends ViewGroup {
* Return the current drawable used as the navigation icon.
*
* @return The navigation icon drawable
+ *
+ * @attr ref android.R.styleable#Toolbar_navigationIcon
*/
@Nullable
public Drawable getNavigationIcon() {
@@ -1316,6 +1338,8 @@ public class Toolbar extends ViewGroup {
final View bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
final LayoutParams toplp = (LayoutParams) topChild.getLayoutParams();
final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutParams();
+ final boolean titleHasWidth = layoutTitle && mTitleTextView.getMeasuredWidth() > 0
+ || layoutSubtitle && mSubtitleTextView.getMeasuredWidth() > 0;
switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
@@ -1343,7 +1367,7 @@ public class Toolbar extends ViewGroup {
break;
}
if (isRtl) {
- final int rd = mTitleMarginStart - collapsingMargins[1];
+ final int rd = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[1];
right -= Math.max(0, rd);
collapsingMargins[1] = Math.max(0, -rd);
int titleRight = right;
@@ -1366,9 +1390,11 @@ public class Toolbar extends ViewGroup {
subtitleRight = subtitleRight - mTitleMarginEnd;
titleTop = subtitleBottom + lp.bottomMargin;
}
- right = Math.min(titleRight, subtitleRight);
+ if (titleHasWidth) {
+ right = Math.min(titleRight, subtitleRight);
+ }
} else {
- final int ld = mTitleMarginStart - collapsingMargins[0];
+ final int ld = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[0];
left += Math.max(0, ld);
collapsingMargins[0] = Math.max(0, -ld);
int titleLeft = left;
@@ -1391,7 +1417,9 @@ public class Toolbar extends ViewGroup {
subtitleLeft = subtitleRight + mTitleMarginEnd;
titleTop = subtitleBottom + lp.bottomMargin;
}
- left = Math.max(titleLeft, subtitleLeft);
+ if (titleHasWidth) {
+ left = Math.max(titleLeft, subtitleLeft);
+ }
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 61b4567..b6e7353 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -23,7 +23,6 @@ import android.app.usage.UsageStatsManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Slog;
import android.widget.AbsListView;
import android.widget.GridView;
@@ -73,6 +72,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -100,7 +100,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private boolean mResolvingHome = false;
private UsageStatsManager mUsm;
- private ArrayMap<String, UsageStats> mStats;
+ private Map<String, UsageStats> mStats;
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
private boolean mRegistered;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index ee406bd..eae4427 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -993,6 +993,6 @@ public final class BatteryStatsHelper {
} catch (RemoteException e) {
Log.w(TAG, "RemoteException:", e);
}
- return null;
+ return new BatteryStatsImpl();
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 299b0e6..69cdbff 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -2487,6 +2487,16 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
}
+ public void noteCurrentTimeChangedLocked() {
+ final long currentTime = System.currentTimeMillis();
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
+ if (isStartClockTimeValid()) {
+ mStartClockTime = currentTime;
+ }
+ }
+
public void noteProcessStartLocked(String name, int uid) {
uid = mapUid(uid);
if (isOnBattery()) {
@@ -4060,7 +4070,20 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ boolean isStartClockTimeValid() {
+ return mStartClockTime > 365*24*60*60*1000L;
+ }
+
@Override public long getStartClockTime() {
+ if (!isStartClockTimeValid()) {
+ // If the last clock time we got was very small, then we hadn't had a real
+ // time yet, so try to get it again.
+ mStartClockTime = System.currentTimeMillis();
+ if (isStartClockTimeValid()) {
+ recordCurrentTimeChangeLocked(mStartClockTime, SystemClock.elapsedRealtime(),
+ SystemClock.uptimeMillis());
+ }
+ }
return mStartClockTime;
}
@@ -6799,6 +6822,16 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ private void recordCurrentTimeChangeLocked(final long currentTime, final long elapsedRealtimeMs,
+ final long uptimeMs) {
+ if (mRecordingHistory) {
+ mHistoryCur.currentTime = currentTime;
+ addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
+ mHistoryCur);
+ mHistoryCur.currentTime = 0;
+ }
+ }
+
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
@@ -8004,6 +8037,10 @@ public final class BatteryStatsImpl extends BatteryStats {
public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
pullPendingStateUpdatesLocked();
+ // Pull the clock time. This may update the time and make a new history entry
+ // if we had originally pulled a time before the RTC was set.
+ long startClockTime = getStartClockTime();
+
final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
@@ -8014,7 +8051,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mStartCount);
out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
- out.writeLong(mStartClockTime);
+ out.writeLong(startClockTime);
out.writeString(mStartPlatformVersion);
out.writeString(mEndPlatformVersion);
mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
@@ -8453,6 +8490,10 @@ public final class BatteryStatsImpl extends BatteryStats {
// Need to update with current kernel wake lock counts.
pullPendingStateUpdatesLocked();
+ // Pull the clock time. This may update the time and make a new history entry
+ // if we had originally pulled a time before the RTC was set.
+ long startClockTime = getStartClockTime();
+
final long uSecUptime = SystemClock.uptimeMillis() * 1000;
final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryRealtime = mOnBatteryTimeBase.getRealtime(uSecRealtime);
@@ -8463,7 +8504,7 @@ public final class BatteryStatsImpl extends BatteryStats {
writeHistory(out, true, false);
out.writeInt(mStartCount);
- out.writeLong(mStartClockTime);
+ out.writeLong(startClockTime);
out.writeString(mStartPlatformVersion);
out.writeString(mEndPlatformVersion);
out.writeLong(mUptime);
@@ -8588,6 +8629,10 @@ public final class BatteryStatsImpl extends BatteryStats {
public void prepareForDumpLocked() {
// Need to retrieve current kernel wake lock stats before printing.
pullPendingStateUpdatesLocked();
+
+ // Pull the clock time. This may update the time and make a new history entry
+ // if we had originally pulled a time before the RTC was set.
+ getStartClockTime();
}
public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 2967938..ba236f3 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -191,6 +191,20 @@ public class EditableInputConnection extends BaseInputConnection {
public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
+ // It is possible that any other bit is used as a valid flag in a future release.
+ // We should reject the entire request in such a case.
+ final int KNOWN_FLAGS_MASK = InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE |
+ InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR;
+ final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK;
+ if (unknownFlags != 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Rejecting requestUpdateCursorAnchorInfo due to unknown flags." +
+ " cursorUpdateMode=" + cursorUpdateMode +
+ " unknownFlags=" + unknownFlags);
+ }
+ return false;
+ }
+
if (mIMM == null) {
// In this case, TYPE_CURSOR_ANCHOR_INFO is not handled.
// TODO: Return some notification code rather than false to indicate method that