diff options
73 files changed, 2405 insertions, 1048 deletions
diff --git a/api/current.txt b/api/current.txt index e7f75f7..f6bc276 100644 --- a/api/current.txt +++ b/api/current.txt @@ -864,6 +864,7 @@ package android { field public static final int paddingBottom = 16842969; // 0x10100d9 field public static final int paddingEnd = 16843700; // 0x10103b4 field public static final int paddingLeft = 16842966; // 0x10100d6 + field public static final int paddingMode = 16843866; // 0x101045a field public static final int paddingRight = 16842968; // 0x10100d8 field public static final int paddingStart = 16843699; // 0x10103b3 field public static final int paddingTop = 16842967; // 0x10100d7 @@ -1640,7 +1641,6 @@ package android { field public static final int selectAll = 16908319; // 0x102001f field public static final int selectTextMode = 16908333; // 0x102002d field public static final int selectedIcon = 16908302; // 0x102000e - field public static final int shared_element = 16908354; // 0x1020042 field public static final int startSelectingText = 16908328; // 0x1020028 field public static final int stopSelectingText = 16908329; // 0x1020029 field public static final int summary = 16908304; // 0x1020010 @@ -2830,6 +2830,12 @@ package android.animation { method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object); } + public abstract class BidirectionalTypeConverter extends android.animation.TypeConverter { + ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>); + method public abstract T convertBack(V); + method public android.animation.BidirectionalTypeConverter<V, T> invert(); + } + public class FloatArrayEvaluator implements android.animation.TypeEvaluator { ctor public FloatArrayEvaluator(); ctor public FloatArrayEvaluator(float[]); @@ -3008,7 +3014,6 @@ package android.animation { public abstract class TypeConverter { ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>); method public abstract V convert(T); - method public T convertBack(V); } public abstract interface TypeEvaluator { @@ -3336,6 +3341,8 @@ package android.app { method public void setContentView(android.view.View); method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); method public final void setDefaultKeyMode(int); + method public void setEnterSharedElementListener(android.app.SharedElementListener); + method public void setExitSharedElementListener(android.app.SharedElementListener); method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable); method public final void setFeatureDrawableAlpha(int, int); method public final void setFeatureDrawableResource(int, int); @@ -3351,7 +3358,6 @@ package android.app { method public final void setResult(int); method public final void setResult(int, android.content.Intent); method public final void setSecondaryProgress(int); - method public void setSharedElementListener(android.app.SharedElementListener); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); @@ -4418,6 +4424,8 @@ package android.app { ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public int describeContents(); + method public java.lang.String getGroup(); + method public java.lang.String getSortKey(); method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent); method public void writeToParcel(android.os.Parcel, int); field public static final java.lang.String CATEGORY_ALARM = "alarm"; @@ -4460,6 +4468,7 @@ package android.app { field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big"; field public static final int FLAG_AUTO_CANCEL = 16; // 0x10 field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40 + field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200 field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80 field public static final int FLAG_INSISTENT = 4; // 0x4 field public static final int FLAG_LOCAL_ONLY = 256; // 0x100 @@ -4510,6 +4519,7 @@ package android.app { method public android.app.Notification.Action clone(); method public int describeContents(); method public android.os.Bundle getExtras(); + method public android.app.RemoteInput[] getRemoteInputs(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public android.app.PendingIntent actionIntent; @@ -4517,14 +4527,20 @@ package android.app { field public java.lang.CharSequence title; } - public static class Notification.Action.Builder { + public static final class Notification.Action.Builder { ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent); ctor public Notification.Action.Builder(android.app.Notification.Action); method public android.app.Notification.Action.Builder addExtras(android.os.Bundle); + method public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput); + method public android.app.Notification.Action.Builder apply(android.app.Notification.Action.Builder.Extender); method public android.app.Notification.Action build(); method public android.os.Bundle getExtras(); } + public static abstract interface Notification.Action.Builder.Extender { + method public abstract android.app.Notification.Action.Builder applyTo(android.app.Notification.Action.Builder); + } + public static class Notification.BigPictureStyle extends android.app.Notification.Style { ctor public Notification.BigPictureStyle(); ctor public Notification.BigPictureStyle(android.app.Notification.Builder); @@ -4548,6 +4564,7 @@ package android.app { method public android.app.Notification.Builder addAction(android.app.Notification.Action); method public android.app.Notification.Builder addExtras(android.os.Bundle); method public android.app.Notification.Builder addPerson(java.lang.String); + method public android.app.Notification.Builder apply(android.app.Notification.Builder.Extender); method public android.app.Notification build(); method public android.os.Bundle getExtras(); method public deprecated android.app.Notification getNotification(); @@ -4563,6 +4580,8 @@ package android.app { method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent); method public android.app.Notification.Builder setExtras(android.os.Bundle); method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean); + method public android.app.Notification.Builder setGroup(java.lang.String); + method public android.app.Notification.Builder setGroupSummary(boolean); method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap); method public android.app.Notification.Builder setLights(int, int, int); method public android.app.Notification.Builder setLocalOnly(boolean); @@ -4575,6 +4594,7 @@ package android.app { method public android.app.Notification.Builder setShowWhen(boolean); method public android.app.Notification.Builder setSmallIcon(int); method public android.app.Notification.Builder setSmallIcon(int, int); + method public android.app.Notification.Builder setSortKey(java.lang.String); method public android.app.Notification.Builder setSound(android.net.Uri); method public android.app.Notification.Builder setSound(android.net.Uri, int); method public android.app.Notification.Builder setStyle(android.app.Notification.Style); @@ -4587,6 +4607,10 @@ package android.app { method public android.app.Notification.Builder setWhen(long); } + public static abstract interface Notification.Builder.Extender { + method public abstract android.app.Notification.Builder applyTo(android.app.Notification.Builder); + } + public static class Notification.InboxStyle extends android.app.Notification.Style { ctor public Notification.InboxStyle(); ctor public Notification.InboxStyle(android.app.Notification.Builder); @@ -4690,6 +4714,31 @@ package android.app { field public static final int STYLE_SPINNER = 0; // 0x0 } + public final class RemoteInput implements android.os.Parcelable { + method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle); + method public int describeContents(); + method public boolean getAllowFreeFormInput(); + method public java.lang.CharSequence[] getChoices(); + method public android.os.Bundle getExtras(); + method public java.lang.CharSequence getLabel(); + method public java.lang.String getResultKey(); + method public static android.os.Bundle getResultsFromIntent(android.content.Intent); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData"; + field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results"; + } + + public static final class RemoteInput.Builder { + ctor public RemoteInput.Builder(java.lang.String); + method public android.app.RemoteInput.Builder addExtras(android.os.Bundle); + method public android.app.RemoteInput build(); + method public android.os.Bundle getExtras(); + method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean); + method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]); + method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence); + } + public class SearchManager implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener { method public android.content.ComponentName getGlobalSearchActivity(); method public android.app.SearchableInfo getSearchableInfo(android.content.ComponentName); @@ -4810,7 +4859,7 @@ package android.app { field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0 } - public class SharedElementListener { + public abstract class SharedElementListener { ctor public SharedElementListener(); method public void handleRejectedSharedElements(java.util.List<android.view.View>); method public void remapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>); @@ -5047,6 +5096,7 @@ package android.app.admin { method public boolean hasGrantedPolicy(android.content.ComponentName, int); method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); + method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String); method public boolean isDeviceOwnerApp(java.lang.String); method public boolean isLockTaskPermitted(android.content.ComponentName); method public boolean isProfileOwnerApp(java.lang.String); @@ -5054,8 +5104,11 @@ package android.app.admin { method public void removeActiveAdmin(android.content.ComponentName); method public boolean resetPassword(java.lang.String, int); method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean); + method public boolean setApplicationBlocked(android.content.ComponentName, java.lang.String, boolean); method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle); + method public int setApplicationsBlocked(android.content.ComponentName, android.content.Intent, boolean); method public void setCameraDisabled(android.content.ComponentName, boolean); + method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String); method public void setKeyguardDisabledFeatures(android.content.ComponentName, int); method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException; method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); @@ -5071,6 +5124,7 @@ package android.app.admin { method public void setPasswordMinimumUpperCase(android.content.ComponentName, int); method public void setPasswordQuality(android.content.ComponentName, int); method public void setProfileEnabled(android.content.ComponentName); + method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); method public int setStorageEncryption(android.content.ComponentName, boolean); method public void wipeData(int); field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"; @@ -8265,6 +8319,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch"; + field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview"; field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi"; field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct"; field public static final int GET_ACTIVITIES = 1; // 0x1 @@ -12821,15 +12876,14 @@ package android.hardware.usb { public class UsbConfiguration implements android.os.Parcelable { method public int describeContents(); - method public int getAttributes(); method public int getId(); method public android.hardware.usb.UsbInterface getInterface(int); method public int getInterfaceCount(); method public int getMaxPower(); method public java.lang.String getName(); + method public boolean isRemoteWakeup(); + method public boolean isSelfPowered(); method public void writeToParcel(android.os.Parcel, int); - field public static final int ATTR_REMOTE_WAKEUP_MASK = 32; // 0x20 - field public static final int ATTR_SELF_POWERED_MASK = 64; // 0x40 field public static final android.os.Parcelable.Creator CREATOR; } @@ -14930,6 +14984,7 @@ package android.media { ctor public RemoteControlClient(android.app.PendingIntent); ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper); method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean); + method public android.media.session.MediaSession getMediaSession(); method public void setMetadataUpdateListener(android.media.RemoteControlClient.OnMetadataUpdateListener); method public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener); method public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener); @@ -20987,6 +21042,7 @@ package android.os { field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user"; field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location"; + field public static final java.lang.String DISALLOW_TELEPHONY = "no_telephony"; field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"; field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone"; field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; @@ -25584,20 +25640,24 @@ package android.service.notification { method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int); method public final void cancelNotification(java.lang.String); method public final void cancelNotifications(java.lang.String[]); + method public java.lang.String[] getActiveNotificationKeys(); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]); - method public java.lang.String[] getOrderedNotificationKeys(); + method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking(); method public android.os.IBinder onBind(android.content.Intent); method public void onListenerConnected(java.lang.String[]); - method public void onNotificationOrderUpdate(); method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification); + method public void onNotificationRankingUpdate(); method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; } - public class NotificationOrderUpdate implements android.os.Parcelable { - ctor public NotificationOrderUpdate(android.os.Parcel); + public static class NotificationListenerService.Ranking implements android.os.Parcelable { method public int describeContents(); + method public int getIndexOfKey(java.lang.String); + method public java.lang.String[] getOrderedKeys(); + method public boolean isAmbient(java.lang.String); + method public boolean isInterceptedByDoNotDisturb(java.lang.String); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/animation/BidirectionalTypeConverter.java b/core/java/android/animation/BidirectionalTypeConverter.java new file mode 100644 index 0000000..960650e --- /dev/null +++ b/core/java/android/animation/BidirectionalTypeConverter.java @@ -0,0 +1,73 @@ +/* + * 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.animation; + +/** + * Abstract base class used convert type T to another type V and back again. This + * is necessary when the value types of in animation are different from the property + * type. BidirectionalTypeConverter is needed when only the final value for the + * animation is supplied to animators. + * @see PropertyValuesHolder#setConverter(TypeConverter) + */ +public abstract class BidirectionalTypeConverter<T, V> extends TypeConverter<T, V> { + private BidirectionalTypeConverter mInvertedConverter; + + public BidirectionalTypeConverter(Class<T> fromClass, Class<V> toClass) { + super(fromClass, toClass); + } + + /** + * Does a conversion from the target type back to the source type. The subclass + * must implement this when a TypeConverter is used in animations and current + * values will need to be read for an animation. + * @param value The Object to convert. + * @return A value of type T, converted from <code>value</code>. + */ + public abstract T convertBack(V value); + + /** + * Returns the inverse of this converter, where the from and to classes are reversed. + * The inverted converter uses this convert to call {@link #convertBack(Object)} for + * {@link #convert(Object)} calls and {@link #convert(Object)} for + * {@link #convertBack(Object)} calls. + * @return The inverse of this converter, where the from and to classes are reversed. + */ + public BidirectionalTypeConverter<V, T> invert() { + if (mInvertedConverter == null) { + mInvertedConverter = new InvertedConverter(this); + } + return mInvertedConverter; + } + + private static class InvertedConverter<From, To> extends BidirectionalTypeConverter<From, To> { + private BidirectionalTypeConverter<To, From> mConverter; + + public InvertedConverter(BidirectionalTypeConverter<To, From> converter) { + super(converter.getTargetType(), converter.getSourceType()); + mConverter = converter; + } + + @Override + public From convertBack(To value) { + return mConverter.convert(value); + } + + @Override + public To convert(From value) { + return mConverter.convertBack(value); + } + } +} diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index c0ce795..130754e 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -610,8 +610,8 @@ public final class ObjectAnimator extends ValueAnimator { * along the way, and an ending value (these values will be distributed evenly across * the duration of the animation). This variant supplies a <code>TypeConverter</code> to * convert from the animated values to the type of the property. If only one value is - * supplied, the <code>TypeConverter</code> must implement - * {@link TypeConverter#convertBack(Object)} to retrieve the current value. + * supplied, the <code>TypeConverter</code> must be a + * {@link android.animation.BidirectionalTypeConverter} to retrieve the current value. * * @param target The object whose property is to be animated. * @param property The property being animated. diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 8fce80a..bf2924c 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -456,7 +456,7 @@ public class PropertyValuesHolder implements Cloneable { * cannot automatically interpolate between objects of unknown type. This variant also * takes a <code>TypeConverter</code> to convert from animated values to the type * of the property. If only one value is supplied, the <code>TypeConverter</code> - * must implement {@link TypeConverter#convertBack(Object)} to retrieve the current + * must be a {@link android.animation.BidirectionalTypeConverter} to retrieve the current * value. * * @param property The property being animated. Should not be null. @@ -635,6 +635,8 @@ public class PropertyValuesHolder implements Cloneable { /** * Sets the converter to convert from the values type to the setter's parameter type. + * If only one value is supplied, <var>converter</var> must be a + * {@link android.animation.BidirectionalTypeConverter}. * @param converter The converter to use to convert values. */ public void setConverter(TypeConverter converter) { @@ -816,12 +818,12 @@ public class PropertyValuesHolder implements Cloneable { private Object convertBack(Object value) { if (mConverter != null) { - value = mConverter.convertBack(value); - if (value == null) { + if (!(mConverter instanceof BidirectionalTypeConverter)) { throw new IllegalArgumentException("Converter " + mConverter.getClass().getName() - + " must implement convertBack and not return null."); + + " must be a BidirectionalTypeConverter"); } + value = ((BidirectionalTypeConverter) mConverter).convertBack(value); } return value; } diff --git a/core/java/android/animation/TypeConverter.java b/core/java/android/animation/TypeConverter.java index 03b3eb5..9ead2ad 100644 --- a/core/java/android/animation/TypeConverter.java +++ b/core/java/android/animation/TypeConverter.java @@ -53,16 +53,4 @@ public abstract class TypeConverter<T, V> { * @return A value of type V, converted from <code>value</code>. */ public abstract V convert(T value); - - /** - * Does a conversion from the target type back to the source type. The subclass - * must implement this when a TypeConverter is used in animations and current - * values will need to be read for an animation. By default, this will return null, - * indicating that back-conversion is not supported. - * @param value The Object to convert. - * @return A value of type T, converted from <code>value</code>. - */ - public T convertBack(V value) { - return null; - } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index e1a94d7..3de971c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -779,7 +779,8 @@ public class Activity extends ContextThemeWrapper final Handler mHandler = new Handler(); private ActivityTransitionState mActivityTransitionState = new ActivityTransitionState(); - SharedElementListener mTransitionListener = new SharedElementListener(); + SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER; + SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER; /** Return the intent that started this activity. */ public Intent getIntent() { @@ -5557,16 +5558,32 @@ public class Activity extends ContextThemeWrapper /** * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, * android.view.View, String)} was used to start an Activity, <var>listener</var> - * will be called to handle shared elements. This requires + * will be called to handle shared elements on the <i>launched</i> Activity. This requires * {@link Window#FEATURE_CONTENT_TRANSITIONS}. * - * @param listener Used to manipulate how shared element transitions function. + * @param listener Used to manipulate shared element transitions on the launched Activity. */ - public void setSharedElementListener(SharedElementListener listener) { + public void setEnterSharedElementListener(SharedElementListener listener) { if (listener == null) { - listener = new SharedElementListener(); + listener = SharedElementListener.NULL_LISTENER; } - mTransitionListener = listener; + mEnterTransitionListener = listener; + } + + /** + * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, + * android.view.View, String)} was used to start an Activity, <var>listener</var> + * will be called to handle shared elements on the <i>launching</i> Activity. Most + * calls will only come when returning from the started Activity. + * This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}. + * + * @param listener Used to manipulate shared element transitions on the launching Activity. + */ + public void setExitSharedElementListener(SharedElementListener listener) { + if (listener == null) { + listener = SharedElementListener.NULL_LISTENER; + } + mExitTransitionListener = listener; } // ------------------ Internal API ------------------ @@ -5882,7 +5899,8 @@ public class Activity extends ContextThemeWrapper * have completed drawing. This is necessary only after an {@link Activity} has been made * opaque using {@link Activity#convertFromTranslucent()} and before it has been drawn * translucent again following a call to {@link - * Activity#convertToTranslucent(TranslucentConversionListener)}. + * Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener, + * ActivityOptions)} * * @hide */ diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 6c6a52f..2acf5b2 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -189,15 +189,17 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { final protected SharedElementListener mListener; protected ResultReceiver mResultReceiver; final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback(); + final protected boolean mIsReturning; public ActivityTransitionCoordinator(Window window, ArrayList<String> allSharedElementNames, ArrayList<String> accepted, ArrayList<String> localNames, - SharedElementListener listener) { + SharedElementListener listener, boolean isReturning) { super(new Handler()); mWindow = window; mListener = listener; mAllSharedElementNames = allSharedElementNames; + mIsReturning = isReturning; setSharedElements(accepted, localNames); if (getViewsTransition() != null) { getDecor().captureTransitioningViews(mTransitioningViews); @@ -330,7 +332,21 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { mResultReceiver = resultReceiver; } - protected abstract Transition getViewsTransition(); + protected Transition getViewsTransition() { + if (mIsReturning) { + return getWindow().getExitTransition(); + } else { + return getWindow().getEnterTransition(); + } + } + + protected Transition getSharedElementTransition() { + if (mIsReturning) { + return getWindow().getSharedElementExitTransition(); + } else { + return getWindow().getSharedElementEnterTransition(); + } + } private static class FixedEpicenterCallback extends Transition.EpicenterCallback { private Rect mEpicenter; @@ -342,4 +358,5 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { return mEpicenter; } } + } diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index 636205b..b40d16c 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -51,7 +51,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private static final long MAX_WAIT_MS = 1500; private boolean mSharedElementTransitionStarted; - private boolean mIsReturning; private Activity mActivity; private boolean mHasStopped; private Handler mHandler; @@ -61,9 +60,8 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { ArrayList<String> sharedElementNames, ArrayList<String> acceptedNames, ArrayList<String> mappedNames) { super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames, - activity.mTransitionListener); + getListener(activity, acceptedNames), acceptedNames != null); mActivity = activity; - mIsReturning = acceptedNames != null; setResultReceiver(resultReceiver); prepareEnter(); Bundle resultReceiverBundle = new Bundle(); @@ -80,6 +78,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } + private static SharedElementListener getListener(Activity activity, + ArrayList<String> acceptedNames) { + boolean isReturning = acceptedNames != null; + return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener; + } + @Override protected void onReceiveResult(int resultCode, Bundle resultData) { switch (resultCode) { @@ -299,7 +303,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { if (sharedElementBundle != null) { Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP); View snapshot = new View(context); - snapshot.setId(com.android.internal.R.id.shared_element); Resources resources = getWindow().getContext().getResources(); snapshot.setBackground(new BitmapDrawable(resources, bitmap)); snapshot.setViewName(name); @@ -420,12 +423,4 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } - @Override - protected Transition getViewsTransition() { - return getWindow().getEnterTransition(); - } - - protected Transition getSharedElementTransition() { - return getWindow().getSharedElementEnterTransition(); - } } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index 43a60a3..1d78b30 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -53,20 +53,22 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { private boolean mIsBackgroundReady; - private boolean mIsReturning; - private boolean mIsCanceled; private Handler mHandler; public ExitTransitionCoordinator(Activity activity, ArrayList<String> names, ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) { - super(activity.getWindow(), names, accepted, mapped, activity.mTransitionListener); - mIsReturning = isReturning; + super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning), + isReturning); mIsBackgroundReady = !mIsReturning; mActivity = activity; } + private static SharedElementListener getListener(Activity activity, boolean isReturning) { + return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener; + } + @Override protected void onReceiveResult(int resultCode, Bundle resultData) { switch (resultCode) { @@ -271,13 +273,4 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { } return -1; } - - @Override - protected Transition getViewsTransition() { - return getWindow().getExitTransition(); - } - - protected Transition getSharedElementTransition() { - return getWindow().getSharedElementExitTransition(); - } } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index fd76b9c4..59b3a27 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -45,6 +45,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.NumberFormat; import java.util.ArrayList; +import java.util.Collections; /** * A class that represents how a persistent notification is to be presented to @@ -370,6 +371,14 @@ public class Notification implements Parcelable */ public static final int FLAG_LOCAL_ONLY = 0x00000100; + /** + * Bit to be bitswise-ored into the {@link #flags} field that should be + * set if this notification is the group summary for a group of notifications. + * Grouped notifications may display in a cluster or stack on devices which + * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. + */ + public static final int FLAG_GROUP_SUMMARY = 0x00000200; + public int flags; /** @hide */ @@ -539,6 +548,34 @@ public class Notification implements Parcelable */ public String category; + private String mGroupKey; + + /** + * Get the key used to group this notification into a cluster or stack + * with other notifications on devices which support such rendering. + */ + public String getGroup() { + return mGroupKey; + } + + private String mSortKey; + + /** + * Get a sort key that orders this notification among other notifications from the + * same package. This can be useful if an external sort was already applied and an app + * would like to preserve this. Notifications will be sorted lexicographically using this + * value, although providing different priorities in addition to providing sort key may + * cause this value to be ignored. + * + * <p>This sort key can also be used to order members of a notification group. See + * {@link Builder#setGroup}. + * + * @see String#compareTo(String) + */ + public String getSortKey() { + return mSortKey; + } + /** * Additional semantic data to be carried around with this Notification. * <p> @@ -706,15 +743,18 @@ public class Notification implements Parcelable */ public static class Action implements Parcelable { private final Bundle mExtras; + private RemoteInput[] mRemoteInputs; /** * Small icon representing the action. */ public int icon; + /** * Title of the action. */ public CharSequence title; + /** * Intent to send when the user invokes this action. May be null, in which case the action * may be rendered in a disabled presentation by the system UI. @@ -728,19 +768,23 @@ public class Notification implements Parcelable actionIntent = PendingIntent.CREATOR.createFromParcel(in); } mExtras = in.readBundle(); + mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR); } + /** * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}. */ public Action(int icon, CharSequence title, PendingIntent intent) { - this(icon, title, intent, new Bundle()); + this(icon, title, intent, new Bundle(), null); } - private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras) { + private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, + RemoteInput[] remoteInputs) { this.icon = icon; this.title = title; this.actionIntent = intent; this.mExtras = extras != null ? extras : new Bundle(); + this.mRemoteInputs = remoteInputs; } /** @@ -751,13 +795,22 @@ public class Notification implements Parcelable } /** + * Get the list of inputs to be collected from the user when this action is sent. + * May return null if no remote inputs were added. + */ + public RemoteInput[] getRemoteInputs() { + return mRemoteInputs; + } + + /** * Builder class for {@link Action} objects. */ - public static class Builder { + public static final class Builder { private final int mIcon; private final CharSequence mTitle; private final PendingIntent mIntent; private final Bundle mExtras; + private ArrayList<RemoteInput> mRemoteInputs; /** * Construct a new builder for {@link Action} object. @@ -766,7 +819,7 @@ public class Notification implements Parcelable * @param intent the {@link PendingIntent} to fire when users trigger this action */ public Builder(int icon, CharSequence title, PendingIntent intent) { - this(icon, title, intent, new Bundle()); + this(icon, title, intent, new Bundle(), null); } /** @@ -775,14 +828,20 @@ public class Notification implements Parcelable * @param action the action to read fields from. */ public Builder(Action action) { - this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras)); + this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras), + action.getRemoteInputs()); } - private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) { + private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras, + RemoteInput[] remoteInputs) { mIcon = icon; mTitle = title; mIntent = intent; mExtras = extras; + if (remoteInputs != null) { + mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length); + Collections.addAll(mRemoteInputs, remoteInputs); + } } /** @@ -809,22 +868,62 @@ public class Notification implements Parcelable } /** + * Add an input to be collected from the user when this action is sent. + * Response values can be retrieved from the fired intent by using the + * {@link RemoteInput#getResultsFromIntent} function. + * @param remoteInput a {@link RemoteInput} to add to the action + * @return this object for method chaining + */ + public Builder addRemoteInput(RemoteInput remoteInput) { + if (mRemoteInputs == null) { + mRemoteInputs = new ArrayList<RemoteInput>(); + } + mRemoteInputs.add(remoteInput); + return this; + } + + /** + * Apply an extender to this action builder. Extenders may be used to add + * metadata or change options on this builder. + */ + public Builder apply(Extender extender) { + extender.applyTo(this); + return this; + } + + /** + * Extender interface for use with {@link #apply}. Extenders may be used to add + * metadata or change options on this builder. + */ + public interface Extender { + /** + * Apply this extender to a notification action builder. + * @param builder the builder to be modified. + * @return the build object for chaining. + */ + public Builder applyTo(Builder builder); + } + + /** * Combine all of the options that have been set and return a new {@link Action} * object. * @return the built action */ public Action build() { - return new Action(mIcon, mTitle, mIntent, mExtras); + RemoteInput[] remoteInputs = mRemoteInputs != null + ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; + return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs); } } @Override public Action clone() { return new Action( - this.icon, - this.title, - this.actionIntent, // safe to alias - new Bundle(this.mExtras)); + icon, + title, + actionIntent, // safe to alias + new Bundle(mExtras), + getRemoteInputs()); } @Override public int describeContents() { @@ -841,6 +940,7 @@ public class Notification implements Parcelable out.writeInt(0); } out.writeBundle(mExtras); + out.writeTypedArray(mRemoteInputs, flags); } public static final Parcelable.Creator<Action> CREATOR = new Parcelable.Creator<Action>() { @@ -960,6 +1060,10 @@ public class Notification implements Parcelable category = parcel.readString(); + mGroupKey = parcel.readString(); + + mSortKey = parcel.readString(); + extras = parcel.readBundle(); // may be null actions = parcel.createTypedArray(Action.CREATOR); // may be null @@ -1037,6 +1141,10 @@ public class Notification implements Parcelable that.category = this.category; + that.mGroupKey = this.mGroupKey; + + that.mSortKey = this.mSortKey; + if (this.extras != null) { try { that.extras = new Bundle(this.extras); @@ -1188,6 +1296,10 @@ public class Notification implements Parcelable parcel.writeString(category); + parcel.writeString(mGroupKey); + + parcel.writeString(mSortKey); + parcel.writeBundle(extras); // null ok parcel.writeTypedArray(actions, 0); // null ok @@ -1325,7 +1437,18 @@ public class Notification implements Parcelable sb.append(" flags=0x"); sb.append(Integer.toHexString(this.flags)); sb.append(String.format(" color=0x%08x", this.color)); - sb.append(" category="); sb.append(this.category); + if (this.category != null) { + sb.append(" category="); + sb.append(this.category); + } + if (this.mGroupKey != null) { + sb.append(" groupKey="); + sb.append(this.mGroupKey); + } + if (this.mSortKey != null) { + sb.append(" sortKey="); + sb.append(this.mSortKey); + } if (actions != null) { sb.append(" "); sb.append(actions.length); @@ -1408,6 +1531,8 @@ public class Notification implements Parcelable private int mProgress; private boolean mProgressIndeterminate; private String mCategory; + private String mGroupKey; + private String mSortKey; private Bundle mExtras; private int mPriority; private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); @@ -1839,6 +1964,51 @@ public class Notification implements Parcelable } /** + * Set this notification to be part of a group of notifications sharing the same key. + * Grouped notifications may display in a cluster or stack on devices which + * support such rendering. + * + * <p>To make this notification the summary for its group, also call + * {@link #setGroupSummary}. A sort order can be specified for group members by using + * {@link #setSortKey}. + * @param groupKey The group key of the group. + * @return this object for method chaining + */ + public Builder setGroup(String groupKey) { + mGroupKey = groupKey; + return this; + } + + /** + * Set this notification to be the group summary for a group of notifications. + * Grouped notifications may display in a cluster or stack on devices which + * support such rendering. Requires a group key also be set using {@link #setGroup}. + * @param isGroupSummary Whether this notification should be a group summary. + * @return this object for method chaining + */ + public Builder setGroupSummary(boolean isGroupSummary) { + setFlag(FLAG_GROUP_SUMMARY, isGroupSummary); + return this; + } + + /** + * Set a sort key that orders this notification among other notifications from the + * same package. This can be useful if an external sort was already applied and an app + * would like to preserve this. Notifications will be sorted lexicographically using this + * value, although providing different priorities in addition to providing sort key may + * cause this value to be ignored. + * + * <p>This sort key can also be used to order members of a notification group. See + * {@link #setGroup}. + * + * @see String#compareTo(String) + */ + public Builder setSortKey(String sortKey) { + mSortKey = sortKey; + return this; + } + + /** * Merge additional metadata into this notification. * * <p>Values within the Bundle will replace existing extras values in this Builder. @@ -1949,7 +2119,7 @@ public class Notification implements Parcelable /** * Specify the value of {@link #visibility}. - + * * @param visibility One of {@link #VISIBILITY_PRIVATE} (the default), * {@link #VISIBILITY_SECRET}, or {@link #VISIBILITY_PUBLIC}. * @@ -1971,6 +2141,28 @@ public class Notification implements Parcelable return this; } + /** + * Apply an extender to this notification builder. Extenders may be used to add + * metadata or change options on this builder. + */ + public Builder apply(Extender extender) { + extender.applyTo(this); + return this; + } + + /** + * Extender interface for use with {@link #apply}. Extenders may be used to add + * metadata or change options on this builder. + */ + public interface Extender { + /** + * Apply this extender to a notification builder. + * @param builder the builder to be modified. + * @return the build object for chaining. + */ + public Builder applyTo(Builder builder); + } + private void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; @@ -2298,6 +2490,8 @@ public class Notification implements Parcelable n.flags |= FLAG_SHOW_LIGHTS; } n.category = mCategory; + n.mGroupKey = mGroupKey; + n.mSortKey = mSortKey; n.priority = mPriority; if (mActions.size() > 0) { n.actions = new Action[mActions.size()]; diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java new file mode 100644 index 0000000..9cfc541 --- /dev/null +++ b/core/java/android/app/RemoteInput.java @@ -0,0 +1,297 @@ +/* + * 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.app; + +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.Intent; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A {@code RemoteInput} object specifies input to be collected from a user to be passed along with + * an intent inside a {@link android.app.PendingIntent} that is sent. + * Always use {@link RemoteInput.Builder} to create instances of this class. + * <p class="note"> See + * <a href="{@docRoot}wear/notifications/remote-input.html">Receiving Voice Input from + * a Notification</a> for more information on how to use this class. + * + * <p>The following example adds a {@code RemoteInput} to a {@link Notification.Action}, + * sets the result key as {@code quick_reply}, and sets the label as {@code Quick reply}. + * Users are prompted to input a response when they trigger the action. The results are sent along + * with the intent and can be retrieved with the result key (provided to the {@link Builder} + * constructor) from the Bundle returned by {@link #getResultsFromIntent}. + * + * <pre class="prettyprint"> + * public static final String KEY_QUICK_REPLY_TEXT = "quick_reply"; + * Notification.Action action = new Notification.Action.Builder( + * R.drawable.reply, "Reply", actionIntent) + * <b>.addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT) + * .setLabel("Quick reply").build()</b>) + * .build();</pre> + * + * <p>When the {@link android.app.PendingIntent} is fired, the intent inside will contain the + * input results if collected. To access these results, use the {@link #getResultsFromIntent} + * function. The result values will present under the result key passed to the {@link Builder} + * constructor. + * + * <pre class="prettyprint"> + * public static final String KEY_QUICK_REPLY_TEXT = "quick_reply"; + * Bundle results = RemoteInput.getResultsFromIntent(intent); + * if (results != null) { + * CharSequence quickReplyResult = results.getCharSequence(KEY_QUICK_REPLY_TEXT); + * }</pre> + */ +public final class RemoteInput implements Parcelable { + /** Label used to denote the clip data type used for remote input transport */ + public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results"; + + /** Extra added to a clip data intent object to hold the results bundle. */ + public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData"; + + private final String mResultKey; + private final CharSequence mLabel; + private final CharSequence[] mChoices; + private final boolean mAllowFreeFormInput; + private final Bundle mExtras; + + private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices, + boolean allowFreeFormInput, Bundle extras) { + this.mResultKey = resultKey; + this.mLabel = label; + this.mChoices = choices; + this.mAllowFreeFormInput = allowFreeFormInput; + this.mExtras = extras; + } + + /** + * Get the key that the result of this input will be set in from the Bundle returned by + * {@link #getResultsFromIntent} when the {@link android.app.PendingIntent} is sent. + */ + public String getResultKey() { + return mResultKey; + } + + /** + * Get the label to display to users when collecting this input. + */ + public CharSequence getLabel() { + return mLabel; + } + + /** + * Get possible input choices. This can be {@code null} if there are no choices to present. + */ + public CharSequence[] getChoices() { + return mChoices; + } + + /** + * Get whether or not users can provide an arbitrary value for + * input. If you set this to {@code false}, users must select one of the + * choices in {@link #getChoices}. An {@link IllegalArgumentException} is thrown + * if you set this to false and {@link #getChoices} returns {@code null} or empty. + */ + public boolean getAllowFreeFormInput() { + return mAllowFreeFormInput; + } + + /** + * Get additional metadata carried around with this remote input. + */ + public Bundle getExtras() { + return mExtras; + } + + /** + * Builder class for {@link RemoteInput} objects. + */ + public static final class Builder { + private final String mResultKey; + private CharSequence mLabel; + private CharSequence[] mChoices; + private boolean mAllowFreeFormInput = true; + private Bundle mExtras = new Bundle(); + + /** + * Create a builder object for {@link RemoteInput} objects. + * @param resultKey the Bundle key that refers to this input when collected from the user + */ + public Builder(String resultKey) { + if (resultKey == null) { + throw new IllegalArgumentException("Result key can't be null"); + } + mResultKey = resultKey; + } + + /** + * Set a label to be displayed to the user when collecting this input. + * @param label The label to show to users when they input a response. + * @return this object for method chaining + */ + public Builder setLabel(CharSequence label) { + mLabel = Notification.safeCharSequence(label); + return this; + } + + /** + * Specifies choices available to the user to satisfy this input. + * @param choices an array of pre-defined choices for users input. + * You must provide a non-null and non-empty array if + * you disabled free form input using {@link #setAllowFreeFormInput}. + * @return this object for method chaining + */ + public Builder setChoices(CharSequence[] choices) { + if (choices == null) { + mChoices = null; + } else { + mChoices = new CharSequence[choices.length]; + for (int i = 0; i < choices.length; i++) { + mChoices[i] = Notification.safeCharSequence(choices[i]); + } + } + return this; + } + + /** + * Specifies whether the user can provide arbitrary values. + * + * @param allowFreeFormInput The default is {@code true}. + * If you specify {@code false}, you must provide a non-null + * and non-empty array to {@link #setChoices} or an + * {@link IllegalArgumentException} is thrown. + * @return this object for method chaining + */ + public Builder setAllowFreeFormInput(boolean allowFreeFormInput) { + mAllowFreeFormInput = allowFreeFormInput; + return this; + } + + /** + * Merge additional metadata into this builder. + * + * <p>Values within the Bundle will replace existing extras values in this Builder. + * + * @see RemoteInput#getExtras + */ + public Builder addExtras(Bundle extras) { + if (extras != null) { + mExtras.putAll(extras); + } + return this; + } + + /** + * Get the metadata Bundle used by this Builder. + * + * <p>The returned Bundle is shared with this Builder. + */ + public Bundle getExtras() { + return mExtras; + } + + /** + * Combine all of the options that have been set and return a new {@link RemoteInput} + * object. + */ + public RemoteInput build() { + return new RemoteInput(mResultKey, mLabel, mChoices, mAllowFreeFormInput, mExtras); + } + } + + private RemoteInput(Parcel in) { + mResultKey = in.readString(); + mLabel = in.readCharSequence(); + mChoices = in.readCharSequenceArray(); + mAllowFreeFormInput = in.readInt() != 0; + mExtras = in.readBundle(); + } + + /** + * Get the remote input results bundle from an intent. The returned Bundle will + * contain a key/value for every result key populated by remote input collector. + * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value. + * @param intent The intent object that fired in response to an action or content intent + * which also had one or more remote input requested. + */ + public static Bundle getResultsFromIntent(Intent intent) { + ClipData clipData = intent.getClipData(); + if (clipData == null) { + return null; + } + ClipDescription clipDescription = clipData.getDescription(); + if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) { + return null; + } + if (clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) { + return clipData.getItemAt(0).getIntent().getExtras().getParcelable(EXTRA_RESULTS_DATA); + } + return null; + } + + /** + * Populate an intent object with the results gathered from remote input. This method + * should only be called by remote input collection services when sending results to a + * pending intent. + * @param remoteInputs The remote inputs for which results are being provided + * @param intent The intent to add remote inputs to. The {@link ClipData} + * field of the intent will be modified to contain the results. + * @param results A bundle holding the remote input results. This bundle should + * be populated with keys matching the result keys specified in + * {@code remoteInputs} with values being the result per key. + */ + public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, + Bundle results) { + Bundle resultsBundle = new Bundle(); + for (RemoteInput remoteInput : remoteInputs) { + Object result = results.get(remoteInput.getResultKey()); + if (result instanceof CharSequence) { + resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result); + } + } + Intent clipIntent = new Intent(); + clipIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle); + intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipIntent)); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(mResultKey); + out.writeCharSequence(mLabel); + out.writeCharSequenceArray(mChoices); + out.writeInt(mAllowFreeFormInput ? 1 : 0); + out.writeBundle(mExtras); + } + + public static final Creator<RemoteInput> CREATOR = new Creator<RemoteInput>() { + @Override + public RemoteInput createFromParcel(Parcel in) { + return new RemoteInput(in); + } + + @Override + public RemoteInput[] newArray(int size) { + return new RemoteInput[size]; + } + }; +} diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementListener.java index d4bc019..e03e42e 100644 --- a/core/java/android/app/SharedElementListener.java +++ b/core/java/android/app/SharedElementListener.java @@ -22,15 +22,27 @@ import java.util.Map; /** * Listener provided in - * {@link Activity#setSharedElementListener(SharedElementListener)} - * to monitor the Activity transitions. The events can be used to customize or override Activity + * {@link Activity#setEnterSharedElementListener(SharedElementListener)} and + * {@link Activity#setExitSharedElementListener(SharedElementListener)} + * to monitor the Activity transitions. The events can be used to customize Activity * Transition behavior. */ -public class SharedElementListener { +public abstract class SharedElementListener { + + static final SharedElementListener NULL_LISTENER = new SharedElementListener() { + }; + /** - * Called to allow the listener to customize the start state of the shared element for - * the shared element entering transition. By default, the shared element is placed in - * the position and with the size of the shared element in the calling Activity or Fragment. + * Called to allow the listener to customize the start state of the shared element when + * transferring in shared element state. + * <p> + * The shared element will start at the size and position of the shared element + * in the launching Activity or Fragment. It will also transfer ImageView scaleType + * and imageMatrix if the shared elements in the calling and called Activities are + * ImageViews. Some applications may want to make additional changes, such as + * changing the clip bounds, scaling, or rotation if the shared element end state + * does not map well to the start state. + * </p> * * @param sharedElementNames The names of the shared elements that were accepted into * the View hierarchy. @@ -44,8 +56,17 @@ public class SharedElementListener { List<View> sharedElements, List<View> sharedElementSnapshots) {} /** - * Called to allow the listener to customize the end state of the shared element for - * the shared element entering transition. + * Called to allow the listener to customize the end state of the shared element when + * transferring in shared element state. + * <p> + * Any customization done in + * {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} + * may need to be modified to the final state of the shared element if it is not + * automatically corrected by layout. For example, rotation or scale will not + * be affected by layout and if changed in {@link #setSharedElementStart(java.util.List, + * java.util.List, java.util.List)}, it will also have to be set here again to correct + * the end state. + * </p> * * @param sharedElementNames The names of the shared elements that were accepted into * the View hierarchy. @@ -59,13 +80,18 @@ public class SharedElementListener { List<View> sharedElements, List<View> sharedElementSnapshots) {} /** - * If nothing is done, all shared elements that were not accepted by - * {@link #remapSharedElements(java.util.List, java.util.Map)} will be Transitioned - * out of the entering scene automatically. Any elements removed from - * rejectedSharedElements must be handled by the ActivityTransitionListener. - * <p>Views in rejectedSharedElements will have their position and size set to the - * position of the calling shared element, relative to the Window decor View. This - * view may be safely added to the decor View's overlay to remain in position.</p> + * Called after {@link #remapSharedElements(java.util.List, java.util.Map)} when + * transferring shared elements in. Any shared elements that have no mapping will be in + * <var>rejectedSharedElements</var>. The elements remaining in + * <var>rejectedSharedElements</var> will be transitioned out of the Scene. If a + * View is removed from <var>rejectedSharedElements</var>, it must be handled by the + * <code>SharedElementListener</code>. + * <p> + * Views in rejectedSharedElements will have their position and size set to the + * position of the calling shared element, relative to the Window decor View and contain + * snapshots of the View from the calling Activity or Fragment. This + * view may be safely added to the decor View's overlay to remain in position. + * </p> * * @param rejectedSharedElements Views containing visual information of shared elements * that are not part of the entering scene. These Views @@ -78,6 +104,7 @@ public class SharedElementListener { /** * Lets the ActivityTransitionListener adjust the mapping of shared element names to * Views. + * * @param names The names of all shared elements transferred from the calling Activity * to the started Activity. * @param sharedElements The mapping of shared element names to Views. The best guess diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 58d707c..48ff5b6 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -911,6 +911,35 @@ public class WallpaperManager { */ public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) { try { + /** + * The framework makes no attempt to limit the window size + * to the maximum texture size. Any window larger than this + * cannot be composited. + * + * Read maximum texture size from system property and scale down + * minimumWidth and minimumHeight accordingly. + */ + int maximumTextureSize; + try { + maximumTextureSize = SystemProperties.getInt("sys.max_texture_size", 0); + } catch (Exception e) { + maximumTextureSize = 0; + } + + if (maximumTextureSize > 0) { + if ((minimumWidth > maximumTextureSize) || + (minimumHeight > maximumTextureSize)) { + float aspect = (float)minimumHeight / (float)minimumWidth; + if (minimumWidth > minimumHeight) { + minimumWidth = maximumTextureSize; + minimumHeight = (int)((minimumWidth * aspect) + 0.5); + } else { + minimumHeight = maximumTextureSize; + minimumWidth = (int)((minimumHeight / aspect) + 0.5); + } + } + } + if (sGlobals.mService == null) { Log.w(TAG, "WallpaperService not running"); } else { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 8884446..18e2a95 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -32,6 +32,7 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.provider.Settings; import android.service.trust.TrustAgentService; import android.util.Log; @@ -2050,6 +2051,68 @@ public class DevicePolicyManager { } /** + * Called by device or profile owner to block or unblock packages. When a package is blocked it + * is unavailable for use, but the data and actual package file remain. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName The name of the package to block or unblock. + * @param blocked {@code true} if the package should be blocked, {@code false} if it should be + * unblocked. + * @return boolean Whether the blocked setting of the package was successfully updated. + */ + public boolean setApplicationBlocked(ComponentName admin, String packageName, + boolean blocked) { + if (mService != null) { + try { + return mService.setApplicationBlocked(admin, packageName, blocked); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return false; + } + + /** + * Called by profile or device owner to block or unblock currently installed packages. This + * should only be called by a profile or device owner running within a managed profile. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param intent An intent matching the app(s) to be updated. All apps that resolve for this + * intent will be updated in the current profile. + * @param blocked {@code true} if the packages should be blocked, {@code false} if they should + * be unblocked. + * @return int The number of activities that matched the intent and were updated. + */ + public int setApplicationsBlocked(ComponentName admin, Intent intent, boolean blocked) { + if (mService != null) { + try { + return mService.setApplicationsBlocked(admin, intent, blocked); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return 0; + } + + /** + * Called by device or profile owner to determine if a package is blocked. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName The name of the package to retrieve the blocked status of. + * @return boolean {@code true} if the package is blocked, {@code false} otherwise. + */ + public boolean isApplicationBlocked(ComponentName admin, String packageName) { + if (mService != null) { + try { + return mService.isApplicationBlocked(admin, packageName); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return false; + } + + /** * Called by profile or device owner to re-enable a system app that was disabled by default * when the managed profile was created. This should only be called from a profile or device * owner running within a managed profile. @@ -2181,4 +2244,42 @@ public class DevicePolicyManager { } return false; } + + /** + * Called by device owners to update {@link Settings.Global} settings. Validation that the value + * of the setting is in the correct form for the setting type should be performed by the caller. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param setting The name of the setting to update. + * @param value The value to update the setting to. + */ + public void setGlobalSetting(ComponentName admin, String setting, String value) { + if (mService != null) { + try { + mService.setGlobalSetting(admin, setting, value); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Called by profile or device owners to update {@link Settings.Secure} settings. Validation + * that the value of the setting is in the correct form for the setting type should be performed + * by the caller. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param setting The name of the setting to update. + * @param value The value to update the setting to. + */ + public void setSecureSetting(ComponentName admin, String setting, String value) { + if (mService != null) { + try { + mService.setSecureSetting(admin, setting, value); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 03ced0f..7257158 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -124,6 +124,10 @@ interface IDevicePolicyManager { void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags); void clearForwardingIntentFilters(in ComponentName admin); + boolean setApplicationBlocked(in ComponentName admin, in String packageName, boolean blocked); + int setApplicationsBlocked(in ComponentName admin, in Intent intent, boolean blocked); + boolean isApplicationBlocked(in ComponentName admin, in String packageName); + void enableSystemApp(in ComponentName admin, in String packageName); int enableSystemAppWithIntent(in ComponentName admin, in Intent intent); @@ -133,4 +137,7 @@ interface IDevicePolicyManager { void setLockTaskComponents(in ComponentName[] components); ComponentName[] getLockTaskComponents(); boolean isLockTaskPermitted(in ComponentName component); + + void setGlobalSetting(in ComponentName who, in String setting, in String value); + void setSecureSetting(in ComponentName who, in String setting, in String value); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 0e2eab7..35bcc02 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1405,6 +1405,14 @@ public abstract class PackageManager { public static final String FEATURE_MANAGEDPROFILES = "android.software.managedprofiles"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device has a full implementation of the android.webkit.* APIs. Devices + * lacking this feature will not have a functioning WebView implementation. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_WEBVIEW = "android.software.webview"; + + /** * Action to external storage service to clean out removed apps. * @hide */ diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 5674154..3f01dd2 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -64,7 +64,6 @@ import java.util.Arrays; * List Resource</a>.</p> */ public class ColorStateList implements Parcelable { - private int[][] mStateSpecs; // must be parallel to mColors private int[] mColors; // must be parallel to mStateSpecs private int mDefaultColor = 0xffff0000; @@ -100,9 +99,9 @@ public class ColorStateList implements Parcelable { public static ColorStateList valueOf(int color) { // TODO: should we collect these eventually? synchronized (sCache) { - WeakReference<ColorStateList> ref = sCache.get(color); - ColorStateList csl = ref != null ? ref.get() : null; + final WeakReference<ColorStateList> ref = sCache.get(color); + ColorStateList csl = ref != null ? ref.get() : null; if (csl != null) { return csl; } @@ -118,8 +117,7 @@ public class ColorStateList implements Parcelable { */ public static ColorStateList createFromXml(Resources r, XmlPullParser parser) throws XmlPullParserException, IOException { - - AttributeSet attrs = Xml.asAttributeSet(parser); + final AttributeSet attrs = Xml.asAttributeSet(parser); int type; while ((type=parser.next()) != XmlPullParser.START_TAG @@ -133,22 +131,22 @@ public class ColorStateList implements Parcelable { return createFromXmlInner(r, parser, attrs); } - /* Create from inside an XML document. Called on a parser positioned at - * a tag in an XML document, tries to create a ColorStateList from that tag. - * Returns null if the tag is not a valid ColorStateList. + /** + * Create from inside an XML document. Called on a parser positioned at a + * tag in an XML document, tries to create a ColorStateList from that tag. + * + * @throws XmlPullParserException if the current tag is not <selector> + * @return A color state list for the current tag. */ private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { - - ColorStateList colorStateList; - + final ColorStateList colorStateList; final String name = parser.getName(); - if (name.equals("selector")) { colorStateList = new ColorStateList(); } else { throw new XmlPullParserException( - parser.getPositionDescription() + ": invalid drawable tag " + name); + parser.getPositionDescription() + ": invalid drawable tag " + name); } colorStateList.inflate(r, parser, attrs); @@ -161,9 +159,8 @@ public class ColorStateList implements Parcelable { * (0-255). */ public ColorStateList withAlpha(int alpha) { - int[] colors = new int[mColors.length]; - - int len = colors.length; + final int[] colors = new int[mColors.length]; + final int len = colors.length; for (int i = 0; i < len; i++) { colors[i] = (mColors[i] & 0xFFFFFF) | (alpha << 24); } @@ -176,7 +173,6 @@ public class ColorStateList implements Parcelable { */ private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { - int type; final int innerDepth = parser.getDepth()+1; @@ -259,10 +255,25 @@ public class ColorStateList implements Parcelable { System.arraycopy(stateSpecList, 0, mStateSpecs, 0, listSize); } + /** + * Indicates whether this color state list contains more than one state spec + * and will change color based on state. + * + * @return True if this color state list changes color based on state, false + * otherwise. + * @see #getColorForState(int[], int) + */ public boolean isStateful() { return mStateSpecs.length > 1; } + /** + * Indicates whether this color state list is opaque, which means that every + * color returned from {@link #getColorForState(int[], int)} has an alpha + * value of 255. + * + * @return True if this color state list is opaque. + */ public boolean isOpaque() { final int n = mColors.length; for (int i = 0; i < n; i++) { diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 1692a79..a78f8e2 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -21,6 +21,7 @@ import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.annotation.Nullable; import android.content.pm.ActivityInfo; import android.graphics.Movie; import android.graphics.drawable.Drawable; @@ -719,12 +720,12 @@ public class Resources { * @param id The desired resource identifier, as generated by the aapt * tool. This integer encodes the package, type, and resource * entry. The value 0 is an invalid identifier. - * @param theme The theme used to style the drawable attributes. + * @param theme The theme used to style the drawable attributes, may be {@code null}. * @return Drawable An object that can be used to draw this resource. * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. */ - public Drawable getDrawable(int id, Theme theme) throws NotFoundException { + public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException { TypedValue value; synchronized (mAccessLock) { value = mTmpValue; @@ -777,12 +778,12 @@ public class Resources { * The value 0 is an invalid identifier. * @param density The desired screen density indicated by the resource as * found in {@link DisplayMetrics}. - * @param theme The theme used to style the drawable attributes. + * @param theme The theme used to style the drawable attributes, may be {@code null}. * @return Drawable An object that can be used to draw this resource. * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. */ - public Drawable getDrawableForDensity(int id, int density, Theme theme) { + public Drawable getDrawableForDensity(int id, int density, @Nullable Theme theme) { TypedValue value; synchronized (mAccessLock) { value = mTmpValue; diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java index 92d6f75..da5c128 100644 --- a/core/java/android/hardware/usb/UsbConfiguration.java +++ b/core/java/android/hardware/usb/UsbConfiguration.java @@ -44,13 +44,13 @@ public class UsbConfiguration implements Parcelable { * Mask for "self-powered" bit in the configuration's attributes. * @see #getAttributes */ - public static final int ATTR_SELF_POWERED_MASK = 1 << 6; + private static final int ATTR_SELF_POWERED = 1 << 6; /** * Mask for "remote wakeup" bit in the configuration's attributes. * @see #getAttributes */ - public static final int ATTR_REMOTE_WAKEUP_MASK = 1 << 5; + private static final int ATTR_REMOTE_WAKEUP = 1 << 5; /** * UsbConfiguration should only be instantiated by UsbService implementation @@ -83,19 +83,23 @@ public class UsbConfiguration implements Parcelable { } /** - * Returns the configuration's attributes field. - * This field contains a bit field with the following flags: + * Returns the self-powered attribute value configuration's attributes field. + * This attribute indicates that the device has a power source other than the USB connection. * - * Bit 7: always set to 1 - * Bit 6: self-powered - * Bit 5: remote wakeup enabled - * Bit 0-4: reserved - * @see #ATTR_SELF_POWERED_MASK - * @see #ATTR_REMOTE_WAKEUP_MASK - * @return the configuration's attributes + * @return the configuration's self-powered attribute */ - public int getAttributes() { - return mAttributes; + public boolean isSelfPowered() { + return (mAttributes & ATTR_SELF_POWERED) != 0; + } + + /** + * Returns the remote-wakeup attribute value configuration's attributes field. + * This attributes that the device may signal the host to wake from suspend. + * + * @return the configuration's remote-wakeup attribute + */ + public boolean isRemoteWakeup() { + return (mAttributes & ATTR_REMOTE_WAKEUP) != 0; } /** diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 6283951..c062b3a 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -104,7 +104,7 @@ public class UsbDeviceConnection { * Sets the current {@link android.hardware.usb.UsbInterface}. * Used to select between two interfaces with the same ID but different alternate setting. * - * @return true if the interface was successfully released + * @return true if the interface was successfully selected */ public boolean setInterface(UsbInterface intf) { return native_set_interface(intf.getId(), intf.getAlternateSetting()); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1837335..80a9598 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1655,9 +1655,16 @@ public class ConnectivityManager { } /** {@hide} */ - public void registerNetworkFactory(Messenger messenger) { + public void registerNetworkFactory(Messenger messenger, String name) { try { - mService.registerNetworkFactory(messenger); + mService.registerNetworkFactory(messenger, name); + } catch (RemoteException e) { } + } + + /** {@hide} */ + public void unregisterNetworkFactory(Messenger messenger) { + try { + mService.unregisterNetworkFactory(messenger); } catch (RemoteException e) { } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 885b8b6..d97b1e9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -153,7 +153,9 @@ interface IConnectivityManager void setAirplaneMode(boolean enable); - void registerNetworkFactory(in Messenger messenger); + void registerNetworkFactory(in Messenger messenger, in String name); + + void unregisterNetworkFactory(in Messenger messenger); void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score); diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index ceedd98..7ea6bae 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -155,9 +155,6 @@ public class ProxyInfo implements Parcelable { mHost = source.getHost(); mPort = source.getPort(); mPacFileUrl = source.mPacFileUrl; - if (mPacFileUrl == null) { - mPacFileUrl = Uri.EMPTY; - } mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } else { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 312cdbe..ee219e3 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -266,6 +266,17 @@ public class UserManager { */ public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; + /** + * Key for user restrictions. Specifies that the user is not allowed to send or receive + * phone calls or text messages. Emergency calls may still be permitted. + * The default value is <code>false</code>. + * <p/> + * Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_TELEPHONY = "no_telephony"; + /** @hide */ public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3; /** @hide */ diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl index d4919eb..b3705d8 100644 --- a/core/java/android/service/notification/INotificationListener.aidl +++ b/core/java/android/service/notification/INotificationListener.aidl @@ -17,15 +17,15 @@ package android.service.notification; import android.service.notification.StatusBarNotification; -import android.service.notification.NotificationOrderUpdate; +import android.service.notification.NotificationRankingUpdate; /** @hide */ oneway interface INotificationListener { - void onListenerConnected(in NotificationOrderUpdate update); + void onListenerConnected(in NotificationRankingUpdate update); void onNotificationPosted(in StatusBarNotification notification, - in NotificationOrderUpdate update); + in NotificationRankingUpdate update); void onNotificationRemoved(in StatusBarNotification notification, - in NotificationOrderUpdate update); - void onNotificationOrderUpdate(in NotificationOrderUpdate update); + in NotificationRankingUpdate update); + void onNotificationRankingUpdate(in NotificationRankingUpdate update); }
\ No newline at end of file diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index e2e9ff4..7f84877 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -24,12 +24,15 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; /** - * A service that receives calls from the system when new notifications are posted or removed. + * A service that receives calls from the system when new notifications are + * posted or removed, or their ranking changed. * <p>To extend this class, you must declare the service in your manifest file with * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> @@ -48,7 +51,7 @@ public abstract class NotificationListenerService extends Service { + "[" + getClass().getSimpleName() + "]"; private INotificationListenerWrapper mWrapper = null; - private String[] mNotificationKeys; + private Ranking mRanking; private INotificationManager mNoMan; @@ -102,11 +105,11 @@ public abstract class NotificationListenerService extends Service { } /** - * Implement this method to be notified when the notification order cahnges. - * - * Call {@link #getOrderedNotificationKeys()} to retrieve the new order. + * Implement this method to be notified when the notification ranking changes. + * <P> + * Call {@link #getCurrentRanking()} to retrieve the new ranking. */ - public void onNotificationOrderUpdate() { + public void onNotificationRankingUpdate() { // optional } @@ -224,6 +227,19 @@ public abstract class NotificationListenerService extends Service { } /** + * Request the list of notification keys in their current ranking order. + * <p> + * You can use the notification keys for subsequent retrieval via + * {@link #getActiveNotifications(String[]) or dismissal via + * {@link #cancelNotifications(String[]). + * + * @return An array of active notification keys, in their ranking order. + */ + public String[] getActiveNotificationKeys() { + return mRanking.getOrderedKeys(); + } + + /** * 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. * @@ -242,15 +258,20 @@ public abstract class NotificationListenerService extends Service { } /** - * Request the list of notification keys in their current natural order. - * You can use the notification keys for subsequent retrieval via - * {@link #getActiveNotifications(String[]) or dismissal via - * {@link #cancelNotifications(String[]). + * Returns current ranking information. + * + * <p> + * The returned object represents the current ranking snapshot and only + * applies for currently active notifications. Hence you must retrieve a + * new Ranking after each notification event such as + * {@link #onNotificationPosted(StatusBarNotification)}, + * {@link #onNotificationRemoved(StatusBarNotification)}, etc. * - * @return An array of active notification keys, in their natural order. + * @return A {@link NotificationListenerService.Ranking} object providing + * access to ranking information */ - public String[] getOrderedNotificationKeys() { - return mNotificationKeys; + public Ranking getCurrentRanking() { + return mRanking; } @Override @@ -308,59 +329,163 @@ public abstract class NotificationListenerService extends Service { private class INotificationListenerWrapper extends INotificationListener.Stub { @Override public void onNotificationPosted(StatusBarNotification sbn, - NotificationOrderUpdate update) { - try { - // protect subclass from concurrent modifications of (@link mNotificationKeys}. - synchronized (mWrapper) { - updateNotificationKeys(update); + NotificationRankingUpdate update) { + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + applyUpdate(update); + try { NotificationListenerService.this.onNotificationPosted(sbn); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationPosted", t); } - } catch (Throwable t) { - Log.w(TAG, "Error running onOrderedNotificationPosted", t); } } @Override public void onNotificationRemoved(StatusBarNotification sbn, - NotificationOrderUpdate update) { - try { - // protect subclass from concurrent modifications of (@link mNotificationKeys}. - synchronized (mWrapper) { - updateNotificationKeys(update); + NotificationRankingUpdate update) { + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + applyUpdate(update); + try { NotificationListenerService.this.onNotificationRemoved(sbn); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationRemoved", t); } - } catch (Throwable t) { - Log.w(TAG, "Error running onNotificationRemoved", t); } } @Override - public void onListenerConnected(NotificationOrderUpdate update) { - try { - // protect subclass from concurrent modifications of (@link mNotificationKeys}. - synchronized (mWrapper) { - updateNotificationKeys(update); - NotificationListenerService.this.onListenerConnected(mNotificationKeys); + public void onListenerConnected(NotificationRankingUpdate update) { + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + applyUpdate(update); + try { + NotificationListenerService.this.onListenerConnected( + mRanking.getOrderedKeys()); + } catch (Throwable t) { + Log.w(TAG, "Error running onListenerConnected", t); } - } catch (Throwable t) { - Log.w(TAG, "Error running onListenerConnected", t); } } @Override - public void onNotificationOrderUpdate(NotificationOrderUpdate update) + public void onNotificationRankingUpdate(NotificationRankingUpdate update) throws RemoteException { - try { - // protect subclass from concurrent modifications of (@link mNotificationKeys}. - synchronized (mWrapper) { - updateNotificationKeys(update); - NotificationListenerService.this.onNotificationOrderUpdate(); + // protect subclass from concurrent modifications of (@link mNotificationKeys}. + synchronized (mWrapper) { + applyUpdate(update); + try { + NotificationListenerService.this.onNotificationRankingUpdate(); + } catch (Throwable t) { + Log.w(TAG, "Error running onNotificationRankingUpdate", t); } - } catch (Throwable t) { - Log.w(TAG, "Error running onNotificationOrderUpdate", t); } } } - private void updateNotificationKeys(NotificationOrderUpdate update) { - // TODO: avoid garbage by comparing the lists - mNotificationKeys = update.getOrderedKeys(); + private void applyUpdate(NotificationRankingUpdate update) { + mRanking = new Ranking(update); + } + + /** + * Provides access to ranking information on currently active + * notifications. + * + * <p> + * Note that this object represents a ranking snapshot that only applies to + * notifications active at the time of retrieval. + */ + public static class Ranking implements Parcelable { + private final NotificationRankingUpdate mRankingUpdate; + + private Ranking(NotificationRankingUpdate rankingUpdate) { + mRankingUpdate = rankingUpdate; + } + + /** + * Request the list of notification keys in their current ranking + * order. + * + * @return An array of active notification keys, in their ranking order. + */ + public String[] getOrderedKeys() { + return mRankingUpdate.getOrderedKeys(); + } + + /** + * Returns the rank of the notification with the given key, that is the + * index of <code>key</code> in the array of keys returned by + * {@link #getOrderedKeys()}. + * + * @return The rank of the notification with the given key; -1 when the + * given key is unknown. + */ + public int getIndexOfKey(String key) { + // TODO: Optimize. + String[] orderedKeys = mRankingUpdate.getOrderedKeys(); + for (int i = 0; i < orderedKeys.length; i++) { + if (orderedKeys[i].equals(key)) { + return i; + } + } + return -1; + } + + /** + * Returns whether the notification with the given key was intercepted + * by "Do not disturb". + */ + public boolean isInterceptedByDoNotDisturb(String key) { + // TODO: Optimize. + for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) { + if (interceptedKey.equals(key)) { + return true; + } + } + return false; + } + + /** + * Returns whether the notification with the given key is an ambient + * notification, that is a notification that doesn't require the user's + * immediate attention. + */ + public boolean isAmbient(String key) { + // TODO: Optimize. + int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex(); + if (firstAmbientIndex < 0) { + return false; + } + String[] orderedKeys = mRankingUpdate.getOrderedKeys(); + for (int i = firstAmbientIndex; i < orderedKeys.length; i++) { + if (orderedKeys[i].equals(key)) { + return true; + } + } + return false; + } + + // ----------- Parcelable + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mRankingUpdate, flags); + } + + public static final Creator<Ranking> CREATOR = new Creator<Ranking>() { + @Override + public Ranking createFromParcel(Parcel source) { + NotificationRankingUpdate rankingUpdate = source.readParcelable(null); + return new Ranking(rankingUpdate); + } + + @Override + public Ranking[] newArray(int size) { + return new Ranking[size]; + } + }; } } diff --git a/core/java/android/service/notification/NotificationOrderUpdate.java b/core/java/android/service/notification/NotificationOrderUpdate.java deleted file mode 100644 index 20e19a3..0000000 --- a/core/java/android/service/notification/NotificationOrderUpdate.java +++ /dev/null @@ -1,62 +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.service.notification; - -import android.os.Parcel; -import android.os.Parcelable; - -public class NotificationOrderUpdate implements Parcelable { - // TODO replace this with an update instead of the whole array - private final String[] mKeys; - - /** @hide */ - public NotificationOrderUpdate(String[] keys) { - this.mKeys = keys; - } - - public NotificationOrderUpdate(Parcel in) { - this.mKeys = in.readStringArray(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeStringArray(this.mKeys); - } - - public static final Parcelable.Creator<NotificationOrderUpdate> CREATOR - = new Parcelable.Creator<NotificationOrderUpdate>() { - public NotificationOrderUpdate createFromParcel(Parcel parcel) { - return new NotificationOrderUpdate(parcel); - } - - public NotificationOrderUpdate[] newArray(int size) { - return new NotificationOrderUpdate[size]; - } - }; - - /** - * @hide - * @return ordered list of keys - */ - String[] getOrderedKeys() { - return mKeys; - } -} diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/service/notification/NotificationRankingUpdate.aidl index 5d50641..1393cb9 100644 --- a/core/java/android/service/notification/NotificationOrderUpdate.aidl +++ b/core/java/android/service/notification/NotificationRankingUpdate.aidl @@ -16,4 +16,4 @@ package android.service.notification; -parcelable NotificationOrderUpdate; +parcelable NotificationRankingUpdate; diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java new file mode 100644 index 0000000..4b13d95 --- /dev/null +++ b/core/java/android/service/notification/NotificationRankingUpdate.java @@ -0,0 +1,77 @@ +/* + * 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.service.notification; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class NotificationRankingUpdate implements Parcelable { + // TODO: Support incremental updates. + private final String[] mKeys; + private final String[] mDndInterceptedKeys; + private final int mFirstAmbientIndex; + + public NotificationRankingUpdate(String[] keys, String[] dndInterceptedKeys, + int firstAmbientIndex) { + mKeys = keys; + mFirstAmbientIndex = firstAmbientIndex; + mDndInterceptedKeys = dndInterceptedKeys; + } + + public NotificationRankingUpdate(Parcel in) { + mKeys = in.readStringArray(); + mFirstAmbientIndex = in.readInt(); + mDndInterceptedKeys = in.readStringArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeStringArray(mKeys); + out.writeInt(mFirstAmbientIndex); + out.writeStringArray(mDndInterceptedKeys); + } + + public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR + = new Parcelable.Creator<NotificationRankingUpdate>() { + public NotificationRankingUpdate createFromParcel(Parcel parcel) { + return new NotificationRankingUpdate(parcel); + } + + public NotificationRankingUpdate[] newArray(int size) { + return new NotificationRankingUpdate[size]; + } + }; + + public String[] getOrderedKeys() { + return mKeys; + } + + public int getFirstAmbientIndex() { + return mFirstAmbientIndex; + } + + public String[] getDndInterceptedKeys() { + return mDndInterceptedKeys; + } +} diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java index 0bd46bc..b17f502 100644 --- a/core/java/android/text/method/QwertyKeyListener.java +++ b/core/java/android/text/method/QwertyKeyListener.java @@ -115,7 +115,7 @@ public class QwertyKeyListener extends BaseKeyListener { if (count > 0 && selStart == selEnd && selStart > 0) { char c = content.charAt(selStart - 1); - if (c == i || c == Character.toUpperCase(i) && view != null) { + if ((c == i || c == Character.toUpperCase(i)) && view != null) { if (showCharacterPicker(view, content, c, false, count)) { resetMetaState(content); return true; diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index c1a4fee..e918119 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -48,6 +48,8 @@ public final class RenderNodeAnimator extends Animator { public static final int Y = 9; public static final int Z = 10; public static final int ALPHA = 11; + // The last value in the enum, used for array size initialization + public static final int LAST_VALUE = ALPHA; // Keep in sync with enum PaintFields in Animator.h public static final int PAINT_STROKE_WIDTH = 0; @@ -86,7 +88,7 @@ public final class RenderNodeAnimator extends Animator { private boolean mStarted = false; private boolean mFinished = false; - public int mapViewPropertyToRenderProperty(int viewProperty) { + public static int mapViewPropertyToRenderProperty(int viewProperty) { return sViewPropertyAnimatorMap.get(viewProperty); } @@ -125,11 +127,15 @@ public final class RenderNodeAnimator extends Animator { } } + static boolean isNativeInterpolator(TimeInterpolator interpolator) { + return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class); + } + private void applyInterpolator() { if (mInterpolator == null) return; long ni; - if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) { + if (isNativeInterpolator(mInterpolator)) { ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator(); } else { long duration = nGetDuration(mNativePtr.get()); diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index 11d2622..3104862 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -19,6 +19,7 @@ package android.view; import android.animation.Animator; import android.animation.ValueAnimator; import android.animation.TimeInterpolator; +import android.os.Build; import java.util.ArrayList; import java.util.HashMap; @@ -109,6 +110,11 @@ public class ViewPropertyAnimator { private ValueAnimator mTempValueAnimator; /** + * A RenderThread-driven backend that may intercept startAnimation + */ + private ViewPropertyAnimatorRT mRTBackend; + + /** * This listener is the mechanism by which the underlying Animator causes changes to the * properties currently being animated, as well as the cleanup after an animation is * complete. @@ -227,7 +233,7 @@ public class ViewPropertyAnimator { * values are used to calculate the animated value for a given animation fraction * during the animation. */ - private static class NameValuesHolder { + static class NameValuesHolder { int mNameConstant; float mFromValue; float mDeltaValue; @@ -247,6 +253,9 @@ public class ViewPropertyAnimator { ViewPropertyAnimator(View view) { mView = view; view.ensureTransformationInfo(); + if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) { + mRTBackend = new ViewPropertyAnimatorRT(view); + } } /** @@ -371,6 +380,10 @@ public class ViewPropertyAnimator { return this; } + Animator.AnimatorListener getListener() { + return mListener; + } + /** * Sets a listener for update events in the underlying ValueAnimator that runs * the property animations. Note that the underlying animator is animating between @@ -390,6 +403,10 @@ public class ViewPropertyAnimator { return this; } + ValueAnimator.AnimatorUpdateListener getUpdateListener() { + return mUpdateListener; + } + /** * Starts the currently pending property animations immediately. Calling <code>start()</code> * is optional because all animations start automatically at the next opportunity. However, @@ -825,12 +842,22 @@ public class ViewPropertyAnimator { return this; } + boolean hasActions() { + return mPendingSetupAction != null + || mPendingCleanupAction != null + || mPendingOnStartAction != null + || mPendingOnEndAction != null; + } + /** * Starts the underlying Animator for a set of properties. We use a single animator that * simply runs from 0 to 1, and then use that fractional value to set each property * value accordingly. */ private void startAnimation() { + if (mRTBackend != null && mRTBackend.startAnimation(this)) { + return; + } mView.setHasTransientState(true); ValueAnimator animator = ValueAnimator.ofFloat(1.0f); ArrayList<NameValuesHolder> nameValueList = diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java new file mode 100644 index 0000000..709efdb --- /dev/null +++ b/core/java/android/view/ViewPropertyAnimatorRT.java @@ -0,0 +1,118 @@ +/* + * 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.view; + +import android.animation.TimeInterpolator; +import android.view.ViewPropertyAnimator.NameValuesHolder; + +import com.android.internal.view.animation.FallbackLUTInterpolator; + +import java.util.ArrayList; + + +/** + * This is a RenderThread driven backend for ViewPropertyAnimator. + */ +class ViewPropertyAnimatorRT { + + private final View mView; + + private RenderNodeAnimator mAnimators[] = new RenderNodeAnimator[RenderNodeAnimator.LAST_VALUE + 1]; + + ViewPropertyAnimatorRT(View view) { + mView = view; + } + + /** + * @return true if ViewPropertyAnimatorRT handled the animation, + * false if ViewPropertyAnimator needs to handle it + */ + public boolean startAnimation(ViewPropertyAnimator parent) { + cancelAnimators(parent.mPendingAnimations); + if (!canHandleAnimator(parent)) { + return false; + } + doStartAnimation(parent); + return true; + } + + private void doStartAnimation(ViewPropertyAnimator parent) { + int size = parent.mPendingAnimations.size(); + + long startDelay = parent.getStartDelay(); + long duration = parent.getDuration(); + TimeInterpolator interpolator = parent.getInterpolator(); + if (!RenderNodeAnimator.isNativeInterpolator(interpolator)) { + interpolator = new FallbackLUTInterpolator(interpolator, duration); + } + for (int i = 0; i < size; i++) { + NameValuesHolder holder = parent.mPendingAnimations.get(i); + int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant); + + RenderNodeAnimator animator = new RenderNodeAnimator(property, holder.mFromValue + holder.mDeltaValue); + animator.setStartDelay(startDelay); + animator.setDuration(duration); + animator.setInterpolator(interpolator); + animator.setTarget(mView); + animator.start(); + } + + parent.mPendingAnimations.clear(); + } + + private boolean canHandleAnimator(ViewPropertyAnimator parent) { + // TODO: Can we eliminate this entirely? + // If RenderNode.animatorProperties() can be toggled to point at staging + // instead then RNA can be used as the animators for software as well + // as the updateListener fallback paths. If this can be toggled + // at the top level somehow, combined with requiresUiRedraw, we could + // ensure that RT does not self-animate, allowing for safe driving of + // the animators from the UI thread using the same mechanisms + // ViewPropertyAnimator does, just with everything sitting on a single + // animator subsystem instead of multiple. + + if (parent.getUpdateListener() != null) { + return false; + } + if (parent.getListener() != null) { + // TODO support + return false; + } + if (!mView.isHardwareAccelerated()) { + // TODO handle this maybe? + return false; + } + if (parent.hasActions()) { + return false; + } + // Here goes nothing... + return true; + } + + private void cancelAnimators(ArrayList<NameValuesHolder> mPendingAnimations) { + int size = mPendingAnimations.size(); + for (int i = 0; i < size; i++) { + NameValuesHolder holder = mPendingAnimations.get(i); + int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant); + if (mAnimators[property] != null) { + mAnimators[property].cancel(); + mAnimators[property] = null; + } + } + } + +} diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java index 1feb943..06838c9 100644 --- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java @@ -24,10 +24,13 @@ import android.view.Choreographer; * Interpolator that builds a lookup table to use. This is a fallback for * building a native interpolator from a TimeInterpolator that is not marked * with {@link HasNativeInterpolator} + * + * This implements TimeInterpolator to allow for easier interop with Animators */ @HasNativeInterpolator -public class FallbackLUTInterpolator implements NativeInterpolatorFactory { +public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator { + private TimeInterpolator mSourceInterpolator; private final float mLut[]; /** @@ -35,6 +38,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory { * interpolator creation */ public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) { + mSourceInterpolator = interpolator; mLut = createLUT(interpolator, duration); } @@ -63,4 +67,9 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory { float[] lut = createLUT(interpolator, duration); return NativeInterpolatorFactoryHelper.createLutInterpolator(lut); } + + @Override + public float getInterpolation(float input) { + return mSourceInterpolator.getInterpolation(input); + } } diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp index 01eaec4..a3c7b0a 100644 --- a/core/jni/android_hardware_UsbRequest.cpp +++ b/core/jni/android_hardware_UsbRequest.cpp @@ -100,18 +100,19 @@ android_hardware_UsbRequest_queue_array(JNIEnv *env, jobject thiz, } request->buffer_length = length; + // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us + request->client_data = (void *)env->NewGlobalRef(thiz); + if (usb_request_queue(request)) { if (request->buffer) { // free our buffer if usb_request_queue fails free(request->buffer); request->buffer = NULL; } + env->DeleteGlobalRef((jobject)request->client_data); return false; - } else { - // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us - request->client_data = (void *)env->NewGlobalRef(thiz); - return true; } + return true; } static jint @@ -152,16 +153,17 @@ android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz, } request->buffer_length = length; + // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us + // we also need this to make sure our native buffer is not deallocated + // while IO is active + request->client_data = (void *)env->NewGlobalRef(thiz); + if (usb_request_queue(request)) { request->buffer = NULL; + env->DeleteGlobalRef((jobject)request->client_data); return false; - } else { - // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us - // we also need this to make sure our native buffer is not deallocated - // while IO is active - request->client_data = (void *)env->NewGlobalRef(thiz); - return true; } + return true; } static jint diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 55e2983..4b03f31 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4497,7 +4497,7 @@ RTL (right-to-left). --> <attr name="autoMirrored" /> <!-- Indicates how layer padding should affect the bounds of subsequent layers. - The default value is nest. --> + The default padding mode value is nest. --> <attr name="paddingMode"> <!-- Nest each layer inside the padding of the previous layer. --> <enum name="nest" value="0" /> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index 6ea0fae..c966a12 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -83,5 +83,4 @@ <item type="id" name="current_scene" /> <item type="id" name="scene_layoutid_cache" /> <item type="id" name="mask" /> - <item type="id" name="shared_element" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 44b25f2b..32ce568 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2177,6 +2177,7 @@ <public type="attr" name="contentInsetEnd" /> <public type="attr" name="contentInsetLeft" /> <public type="attr" name="contentInsetRight" /> + <public type="attr" name="paddingMode" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> @@ -2186,7 +2187,6 @@ <public-padding type="id" name="l_resource_pad" end="0x01020040" /> <public type="id" name="mask" /> - <public type="id" name="shared_element" /> <public-padding type="style" name="l_resource_pad" end="0x01030200" /> diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index c78096a..911fb96 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -512,13 +512,12 @@ public abstract class Drawable { } /** - * Indicates whether this view will change its appearance based on state. - * Clients can use this to determine whether it is necessary to calculate - * their state and call setState. - * - * @return True if this view changes its appearance based on state, false - * otherwise. + * Indicates whether this drawable will change its appearance based on + * state. Clients can use this to determine whether it is necessary to + * calculate their state and call setState. * + * @return True if this drawable changes its appearance based on state, + * false otherwise. * @see #setState(int[]) */ public boolean isStateful() { @@ -1005,6 +1004,11 @@ public abstract class Drawable { return createFromXmlInnerThemed(r, parser, attrs, null); } + /** + * Create a themed drawable from inside an XML document. Called on a parser + * positioned at a tag in an XML document, tries to create a Drawable from + * that tag. Returns null if the tag is not a valid drawable. + */ public static Drawable createFromXmlInnerThemed(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { final Drawable drawable; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 373d894..f446000 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -38,10 +38,12 @@ import java.io.IOException; * order, so the element with the largest index will be drawn on top. * <p> * It can be defined in an XML file with the <code><layer-list></code> element. - * Each Drawable in the layer is defined in a nested <code><item></code>. For more - * information, see the guide to <a - * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> + * Each Drawable in the layer is defined in a nested <code><item></code>. + * <p> + * For more information, see the guide to + * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. * + * @attr ref android.R.styleable#LayerDrawable_paddingMode * @attr ref android.R.styleable#LayerDrawableItem_left * @attr ref android.R.styleable#LayerDrawableItem_top * @attr ref android.R.styleable#LayerDrawableItem_right @@ -53,10 +55,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** * Padding mode used to nest each layer inside the padding of the previous * layer. + * + * @see #setPaddingMode(int) */ public static final int PADDING_MODE_NEST = 0; - /** Padding mode used to stack each layer directly atop the previous layer. */ + /** + * Padding mode used to stack each layer directly atop the previous layer. + * + * @see #setPaddingMode(int) + */ public static final int PADDING_MODE_STACK = 1; LayerState mLayerState; @@ -127,9 +135,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); - final TypedArray a = obtainAttributes( - r, theme, attrs, R.styleable.LayerDrawable); - inflateStateFromTypedArray(a); + final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); + updateStateFromTypedArray(a); a.recycle(); inflateLayers(r, parser, attrs, theme); @@ -141,25 +148,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** * Initializes the constant state from the values in the typed array. */ - private void inflateStateFromTypedArray(TypedArray a) { + private void updateStateFromTypedArray(TypedArray a) { final LayerState state = mLayerState; // Extract the theme attributes, if any. final int[] themeAttrs = a.extractThemeAttrs(); state.mThemeAttrs = themeAttrs; - if (themeAttrs == null || themeAttrs[R.styleable.LayerDrawable_opacity] == 0) { - mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, PixelFormat.UNKNOWN); - } - - if (themeAttrs == null || themeAttrs[R.styleable.LayerDrawable_autoMirrored] == 0) { - state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored, false); - } + mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, mOpacityOverride); - if (themeAttrs == null || themeAttrs[R.styleable.LayerDrawableItem_drawable] == 0) { - state.mPaddingMode = a.getInteger( - R.styleable.LayerDrawableItem_drawable, PADDING_MODE_NEST); - } + state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored, + state.mAutoMirrored); + state.mPaddingMode = a.getInteger(R.styleable.LayerDrawable_paddingMode, + state.mPaddingMode); } /** @@ -181,9 +182,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; } - a = obtainAttributes( - r, theme, attrs, R.styleable.LayerDrawableItem); + a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); + final int[] themeAttrs = a.extractThemeAttrs(); final int left = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_left, 0); final int top = a.getDimensionPixelOffset( @@ -197,7 +198,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int id = a.getResourceId( R.styleable.LayerDrawableItem_id, View.NO_ID); - // TODO: Cache typed array, if necessary. a.recycle(); final Drawable dr; @@ -214,7 +214,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme); } - addLayer(dr, id, left, top, right, bottom); + addLayer(dr, themeAttrs, id, left, top, right, bottom); } } @@ -224,7 +224,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final LayerState state = mLayerState; if (state == null) { - throw new RuntimeException("Can't apply theme to <layer-list> with no constant state"); + return; } final int[] themeAttrs = state.mThemeAttrs; @@ -239,9 +239,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - final Drawable layer = array[i].mDrawable; - if (layer.canApplyTheme()) { - layer.applyTheme(t); + final ChildDrawable layer = array[i]; + final Drawable d = layer.mDrawable; + if (d.canApplyTheme()) { + d.applyTheme(t); } } @@ -249,26 +250,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { onStateChange(getState()); } - /** - * Updates the constant state from the values in the typed array. - */ - private void updateStateFromTypedArray(TypedArray a) { - final LayerState state = mLayerState; - - if (a.hasValue(R.styleable.LayerDrawable_opacity)) { - mOpacityOverride = a.getInt(R.styleable.LayerDrawable_opacity, PixelFormat.UNKNOWN); - } - - if (a.hasValue(R.styleable.LayerDrawable_autoMirrored)) { - state.mAutoMirrored = a.getBoolean(R.styleable.LayerDrawable_autoMirrored, false); - } - - if (a.hasValue(R.styleable.LayerDrawableItem_drawable)) { - state.mPaddingMode = a.getInteger( - R.styleable.LayerDrawableItem_drawable, PADDING_MODE_NEST); - } - } - @Override public boolean canApplyTheme() { final LayerState state = mLayerState; @@ -283,14 +264,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = state.mChildren; final int N = state.mNum; for (int i = 0; i < N; i++) { - if (array[i].mDrawable.canApplyTheme()) { + final ChildDrawable layer = array[i]; + if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) { return true; } } return false; } - + /** * @hide */ @@ -315,13 +297,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * Add a new layer to this drawable. The new layer is identified by an id. * * @param layer The drawable to add as a layer. + * @param themeAttrs Theme attributes extracted from the layer. * @param id The id of the new layer. * @param left The left padding of the new layer. * @param top The top padding of the new layer. * @param right The right padding of the new layer. * @param bottom The bottom padding of the new layer. */ - private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) { + private void addLayer(Drawable layer, int[] themeAttrs, int id, int left, int top, int right, + int bottom) { final LayerState st = mLayerState; final int N = st.mChildren != null ? st.mChildren.length : 0; final int i = st.mNum; @@ -339,6 +323,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable childDrawable = new ChildDrawable(); st.mChildren[i] = childDrawable; childDrawable.mId = id; + childDrawable.mThemeAttrs = themeAttrs; childDrawable.mDrawable = layer; childDrawable.mDrawable.setAutoMirrored(isAutoMirrored()); childDrawable.mInsetL = left; @@ -471,8 +456,14 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * * @param mode padding mode, one of: * <ul> - * <li>{@link #PADDING_MODE_NEST} <li>{@link #PADDING_MODE_STACK} + * <li>{@link #PADDING_MODE_NEST} to nest each layer inside the + * padding of the previous layer + * <li>{@link #PADDING_MODE_STACK} to stack each layer directly + * atop the previous layer * </ul> + * + * @see #getPaddingMode() + * @attr ref android.R.styleable#LayerDrawable_paddingMode */ public void setPaddingMode(int mode) { if (mLayerState.mPaddingMode != mode) { @@ -482,7 +473,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** * @return the current padding mode + * * @see #setPaddingMode(int) + * @attr ref android.R.styleable#LayerDrawable_paddingMode */ public int getPaddingMode() { return mLayerState.mPaddingMode; @@ -905,7 +898,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private boolean mHaveIsStateful; private boolean mIsStateful; - private boolean mAutoMirrored; + private boolean mAutoMirrored = false; private int mPaddingMode = PADDING_MODE_NEST; diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index edf1091..5f9d1cd 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -145,6 +145,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { * Sets the start angle for rotation. * * @param fromDegrees Starting angle in degrees + * + * @see #getFromDegrees() + * @attr ref android.R.styleable#RotateDrawable_fromDegrees */ public void setFromDegrees(float fromDegrees) { if (mState.mFromDegrees != fromDegrees) { @@ -155,6 +158,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { /** * @return The starting angle for rotation in degrees + * + * @see #setFromDegrees(float) + * @attr ref android.R.styleable#RotateDrawable_fromDegrees */ public float getFromDegrees() { return mState.mFromDegrees; @@ -164,6 +170,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { * Sets the end angle for rotation. * * @param toDegrees Ending angle in degrees + * + * @see #getToDegrees() + * @attr ref android.R.styleable#RotateDrawable_toDegrees */ public void setToDegrees(float toDegrees) { if (mState.mToDegrees != toDegrees) { @@ -174,6 +183,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { /** * @return The ending angle for rotation in degrees + * + * @see #setToDegrees(float) + * @attr ref android.R.styleable#RotateDrawable_toDegrees */ public float getToDegrees() { return mState.mToDegrees; @@ -186,7 +198,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { * relative, the position represents a fraction of the drawable * width. Otherwise, the position represents an absolute value in * pixels. + * * @see #setPivotXRelative(boolean) + * @attr ref android.R.styleable#RotateDrawable_pivotX */ public void setPivotX(float pivotX) { if (mState.mPivotX == pivotX) { @@ -197,7 +211,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { /** * @return X position around which to rotate + * * @see #setPivotX(float) + * @attr ref android.R.styleable#RotateDrawable_pivotX */ public float getPivotX() { return mState.mPivotX; @@ -209,6 +225,8 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { * * @param relative True if the X pivot represents a fraction of the drawable * width, or false if it represents an absolute value in pixels + * + * @see #isPivotXRelative() */ public void setPivotXRelative(boolean relative) { if (mState.mPivotXRel == relative) { @@ -220,6 +238,7 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { /** * @return True if the X pivot represents a fraction of the drawable width, * or false if it represents an absolute value in pixels + * * @see #setPivotXRelative(boolean) */ public boolean isPivotXRelative() { @@ -233,7 +252,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { * relative, the position represents a fraction of the drawable * height. Otherwise, the position represents an absolute value * in pixels. - * @see #setPivotYRelative(boolean) + * + * @see #getPivotY() + * @attr ref android.R.styleable#RotateDrawable_pivotY */ public void setPivotY(float pivotY) { if (mState.mPivotY == pivotY) { @@ -244,7 +265,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { /** * @return Y position around which to rotate + * * @see #setPivotY(float) + * @attr ref android.R.styleable#RotateDrawable_pivotY */ public float getPivotY() { return mState.mPivotY; @@ -256,6 +279,8 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { * * @param relative True if the Y pivot represents a fraction of the drawable * height, or false if it represents an absolute value in pixels + * + * @see #isPivotYRelative() */ public void setPivotYRelative(boolean relative) { if (mState.mPivotYRel == relative) { @@ -267,6 +292,7 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { /** * @return True if the Y pivot represents a fraction of the drawable height, * or false if it represents an absolute value in pixels + * * @see #setPivotYRelative(boolean) */ public boolean isPivotYRelative() { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 3a3f76d..575667d 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2557,60 +2557,191 @@ public class AudioManager { // class is not used by other parts of the framework, which instead use definitions and methods // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. - /** {@hide} The audio output device code for the small speaker at the front of the device used + /** @hide + * The audio output device code for the small speaker at the front of the device used * when placing calls. Does not refer to an in-ear headphone without attached microphone, * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a * {@link #DEVICE_OUT_WIRED_HEADPHONE}. */ public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE; - /** {@hide} The audio output device code for the built-in speaker */ + /** @hide + * The audio output device code for the built-in speaker */ public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER; - /** {@hide} The audio output device code for a wired headset with attached microphone */ + /** @hide + * The audio output device code for a wired headset with attached microphone */ public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET; - /** {@hide} The audio output device code for a wired headphone without attached microphone */ + /** @hide + * The audio output device code for a wired headphone without attached microphone */ public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; - /** {@hide} The audio output device code for generic Bluetooth SCO, for voice */ + /** @hide + * The audio output device code for generic Bluetooth SCO, for voice */ public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; - /** {@hide} The audio output device code for Bluetooth SCO Headset Profile (HSP) and - * Hands-Free Profile (HFP), for voice + /** @hide + * The audio output device code for Bluetooth SCO Headset Profile (HSP) and + * Hands-Free Profile (HFP), for voice */ public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; - /** {@hide} The audio output device code for Bluetooth SCO car audio, for voice */ + /** @hide + * The audio output device code for Bluetooth SCO car audio, for voice */ public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; - /** {@hide} The audio output device code for generic Bluetooth A2DP, for music */ + /** @hide + * The audio output device code for generic Bluetooth A2DP, for music */ public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; - /** {@hide} The audio output device code for Bluetooth A2DP headphones, for music */ + /** @hide + * The audio output device code for Bluetooth A2DP headphones, for music */ public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; - /** {@hide} The audio output device code for Bluetooth A2DP external speaker, for music */ + /** @hide + * The audio output device code for Bluetooth A2DP external speaker, for music */ public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; - /** {@hide} The audio output device code for S/PDIF or HDMI */ + /** @hide + * The audio output device code for S/PDIF (legacy) or HDMI + * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */ public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL; - /** {@hide} The audio output device code for an analog wired headset attached via a + /** @hide + * The audio output device code for HDMI */ + public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI; + /** @hide + * The audio output device code for an analog wired headset attached via a * docking station */ public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; - /** {@hide} The audio output device code for a digital wired headset attached via a + /** @hide + * The audio output device code for a digital wired headset attached via a * docking station */ public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; - /** {@hide} The audio output device code for a USB audio accessory. The accessory is in USB host + /** @hide + * The audio output device code for a USB audio accessory. The accessory is in USB host * mode and the Android device in USB device mode */ public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY; - /** {@hide} The audio output device code for a USB audio device. The device is in USB device + /** @hide + * The audio output device code for a USB audio device. The device is in USB device * mode and the Android device in USB host mode */ public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE; - /** {@hide} This is not used as a returned value from {@link #getDevicesForStream}, but could be + /** @hide + * The audio output device code for projection output. + */ + public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; + /** @hide + * The audio output device code the telephony voice TX path. + */ + public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX; + /** @hide + * The audio output device code for an analog jack with line impedance detected. + */ + public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE; + /** @hide + * The audio output device code for HDMI Audio Return Channel. + */ + public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC; + /** @hide + * The audio output device code for S/PDIF digital connection. + */ + public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF; + /** @hide + * The audio output device code for built-in FM transmitter. + */ + public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; + /** @hide + * This is not used as a returned value from {@link #getDevicesForStream}, but could be * used in the future in a set method to select whatever default device is chosen by the * platform-specific implementation. */ public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT; + /** @hide + * The audio input device code for default built-in microphone + */ + public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC; + /** @hide + * The audio input device code for a Bluetooth SCO headset + */ + public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = + AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; + /** @hide + * The audio input device code for wired headset microphone + */ + public static final int DEVICE_IN_WIRED_HEADSET = + AudioSystem.DEVICE_IN_WIRED_HEADSET; + /** @hide + * The audio input device code for HDMI + */ + public static final int DEVICE_IN_HDMI = + AudioSystem.DEVICE_IN_HDMI; + /** @hide + * The audio input device code for telephony voice RX path + */ + public static final int DEVICE_IN_TELEPHONY_RX = + AudioSystem.DEVICE_IN_TELEPHONY_RX; + /** @hide + * The audio input device code for built-in microphone pointing to the back + */ + public static final int DEVICE_IN_BACK_MIC = + AudioSystem.DEVICE_IN_BACK_MIC; + /** @hide + * The audio input device code for analog from a docking station + */ + public static final int DEVICE_IN_ANLG_DOCK_HEADSET = + AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET; + /** @hide + * The audio input device code for digital from a docking station + */ + public static final int DEVICE_IN_DGTL_DOCK_HEADSET = + AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET; + /** @hide + * The audio input device code for a USB audio accessory. The accessory is in USB host + * mode and the Android device in USB device mode + */ + public static final int DEVICE_IN_USB_ACCESSORY = + AudioSystem.DEVICE_IN_USB_ACCESSORY; + /** @hide + * The audio input device code for a USB audio device. The device is in USB device + * mode and the Android device in USB host mode + */ + public static final int DEVICE_IN_USB_DEVICE = + AudioSystem.DEVICE_IN_USB_DEVICE; + /** @hide + * The audio input device code for a FM radio tuner + */ + public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER; + /** @hide + * The audio input device code for a TV tuner + */ + public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER; + /** @hide + * The audio input device code for an analog jack with line impedance detected + */ + public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE; + /** @hide + * The audio input device code for a S/PDIF digital connection + */ + public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF; + + /** + * Return true if the device code corresponds to an output device. + * @hide + */ + public static boolean isOutputDevice(int device) + { + return (device & AudioSystem.DEVICE_BIT_IN) == 0; + } + + /** + * Return true if the device code corresponds to an input device. + * @hide + */ + public static boolean isInputDevice(int device) + { + return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN; + } + + /** * Return the enabled devices for the specified output stream type. * @@ -2635,9 +2766,17 @@ public class AudioManager { * {@link #DEVICE_OUT_BLUETOOTH_A2DP}, * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}, * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER}, - * {@link #DEVICE_OUT_AUX_DIGITAL}, + * {@link #DEVICE_OUT_HDMI}, * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET}, * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}. + * {@link #DEVICE_OUT_USB_ACCESSORY}. + * {@link #DEVICE_OUT_USB_DEVICE}. + * {@link #DEVICE_OUT_REMOTE_SUBMIX}. + * {@link #DEVICE_OUT_TELEPHONY_TX}. + * {@link #DEVICE_OUT_LINE}. + * {@link #DEVICE_OUT_HDMI_ARC}. + * {@link #DEVICE_OUT_SPDIF}. + * {@link #DEVICE_OUT_FM}. * {@link #DEVICE_OUT_DEFAULT} is not used here. * * The implementation may support additional device codes beyond those listed, so diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index bb8cfa6..6e623a5 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -423,7 +423,7 @@ public class AudioService extends IAudioService.Stub { public final static int STREAM_REMOTE_MUSIC = -200; // Devices for which the volume is fixed and VolumePanel slider should be disabled - final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL | + final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ALL_USB; @@ -2895,7 +2895,7 @@ public class AudioService extends IAudioService.Stub { public String getSettingNameForDevice(int device) { String name = mVolumeIndexSettingName; - String suffix = AudioSystem.getDeviceName(device); + String suffix = AudioSystem.getOutputDeviceName(device); if (suffix.isEmpty()) { return name; } @@ -3935,7 +3935,7 @@ public class AudioService extends IAudioService.Stub { // sent if none of these devices is connected. int mBecomingNoisyIntentDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | - AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL | + AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ALL_USB; @@ -3992,7 +3992,7 @@ public class AudioService extends IAudioService.Stub { } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) { connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); - } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) { + } else if (device == AudioSystem.DEVICE_OUT_HDMI) { connType = AudioRoutesInfo.MAIN_HDMI; intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG); } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 5ddb198..0c45443 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -234,11 +234,17 @@ public class AudioSystem public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100; public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200; public static final int DEVICE_OUT_AUX_DIGITAL = 0x400; + public static final int DEVICE_OUT_HDMI = DEVICE_OUT_AUX_DIGITAL; public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800; public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000; public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000; public static final int DEVICE_OUT_USB_DEVICE = 0x4000; public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000; + public static final int DEVICE_OUT_TELEPHONY_TX = 0x10000; + public static final int DEVICE_OUT_LINE = 0x20000; + public static final int DEVICE_OUT_HDMI_ARC = 0x40000; + public static final int DEVICE_OUT_SPDIF = 0x80000; + public static final int DEVICE_OUT_FM = 0x100000; public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; @@ -252,12 +258,17 @@ public class AudioSystem DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - DEVICE_OUT_AUX_DIGITAL | + DEVICE_OUT_HDMI | DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET | DEVICE_OUT_USB_ACCESSORY | DEVICE_OUT_USB_DEVICE | DEVICE_OUT_REMOTE_SUBMIX | + DEVICE_OUT_TELEPHONY_TX | + DEVICE_OUT_LINE | + DEVICE_OUT_HDMI_ARC | + DEVICE_OUT_SPDIF | + DEVICE_OUT_FM | DEVICE_OUT_DEFAULT); public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | @@ -275,13 +286,20 @@ public class AudioSystem public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = DEVICE_BIT_IN | 0x8; public static final int DEVICE_IN_WIRED_HEADSET = DEVICE_BIT_IN | 0x10; public static final int DEVICE_IN_AUX_DIGITAL = DEVICE_BIT_IN | 0x20; + public static final int DEVICE_IN_HDMI = DEVICE_IN_AUX_DIGITAL; public static final int DEVICE_IN_VOICE_CALL = DEVICE_BIT_IN | 0x40; + public static final int DEVICE_IN_TELEPHONY_RX = DEVICE_IN_VOICE_CALL; public static final int DEVICE_IN_BACK_MIC = DEVICE_BIT_IN | 0x80; public static final int DEVICE_IN_REMOTE_SUBMIX = DEVICE_BIT_IN | 0x100; public static final int DEVICE_IN_ANLG_DOCK_HEADSET = DEVICE_BIT_IN | 0x200; public static final int DEVICE_IN_DGTL_DOCK_HEADSET = DEVICE_BIT_IN | 0x400; public static final int DEVICE_IN_USB_ACCESSORY = DEVICE_BIT_IN | 0x800; public static final int DEVICE_IN_USB_DEVICE = DEVICE_BIT_IN | 0x1000; + public static final int DEVICE_IN_FM_TUNER = DEVICE_BIT_IN | 0x2000; + public static final int DEVICE_IN_TV_TUNER = DEVICE_BIT_IN | 0x4000; + public static final int DEVICE_IN_LINE = DEVICE_BIT_IN | 0x8000; + public static final int DEVICE_IN_SPDIF = DEVICE_BIT_IN | 0x10000; + public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT; public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | @@ -289,14 +307,18 @@ public class AudioSystem DEVICE_IN_BUILTIN_MIC | DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | - DEVICE_IN_AUX_DIGITAL | - DEVICE_IN_VOICE_CALL | + DEVICE_IN_HDMI | + DEVICE_IN_TELEPHONY_RX | DEVICE_IN_BACK_MIC | DEVICE_IN_REMOTE_SUBMIX | DEVICE_IN_ANLG_DOCK_HEADSET | DEVICE_IN_DGTL_DOCK_HEADSET | DEVICE_IN_USB_ACCESSORY | DEVICE_IN_USB_DEVICE | + DEVICE_IN_FM_TUNER | + DEVICE_IN_TV_TUNER | + DEVICE_IN_LINE | + DEVICE_IN_SPDIF | DEVICE_IN_DEFAULT); public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET; public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY | @@ -318,13 +340,19 @@ public class AudioSystem public static final String DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME = "bt_a2dp_hp"; public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk"; public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital"; + public static final String DEVICE_OUT_HDMI_NAME = "hdmi"; public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock"; public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock"; public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory"; public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device"; public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix"; + public static final String DEVICE_OUT_TELEPHONY_TX_NAME = "telephony_tx"; + public static final String DEVICE_OUT_LINE_NAME = "line"; + public static final String DEVICE_OUT_HDMI_ARC_NAME = "hmdi_arc"; + public static final String DEVICE_OUT_SPDIF_NAME = "spdif"; + public static final String DEVICE_OUT_FM_NAME = "fm_transmitter"; - public static String getDeviceName(int device) + public static String getOutputDeviceName(int device) { switch(device) { case DEVICE_OUT_EARPIECE: @@ -347,8 +375,8 @@ public class AudioSystem return DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME; case DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: return DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME; - case DEVICE_OUT_AUX_DIGITAL: - return DEVICE_OUT_AUX_DIGITAL_NAME; + case DEVICE_OUT_HDMI: + return DEVICE_OUT_HDMI_NAME; case DEVICE_OUT_ANLG_DOCK_HEADSET: return DEVICE_OUT_ANLG_DOCK_HEADSET_NAME; case DEVICE_OUT_DGTL_DOCK_HEADSET: @@ -359,12 +387,23 @@ public class AudioSystem return DEVICE_OUT_USB_DEVICE_NAME; case DEVICE_OUT_REMOTE_SUBMIX: return DEVICE_OUT_REMOTE_SUBMIX_NAME; + case DEVICE_OUT_TELEPHONY_TX: + return DEVICE_OUT_TELEPHONY_TX_NAME; + case DEVICE_OUT_LINE: + return DEVICE_OUT_LINE_NAME; + case DEVICE_OUT_HDMI_ARC: + return DEVICE_OUT_HDMI_ARC_NAME; + case DEVICE_OUT_SPDIF: + return DEVICE_OUT_SPDIF_NAME; + case DEVICE_OUT_FM: + return DEVICE_OUT_FM_NAME; case DEVICE_OUT_DEFAULT: default: return ""; } } + // phone state, match audio_mode??? public static final int PHONE_STATE_OFFCALL = 0; public static final int PHONE_STATE_RINGING = 1; diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 37f45c2..26ae3cc 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -407,6 +407,19 @@ public class RemoteControlClient } /** + * Get a {@link MediaSession} associated with this RCC. It will only have a + * session while it is registered with + * {@link AudioManager#registerRemoteControlClient}. The session returned + * should not be modified directly by the application but may be used with + * other APIs that require a session. + * + * @return A media session object or null. + */ + public MediaSession getMediaSession() { + return mSession; + } + + /** * Class used to modify metadata in a {@link RemoteControlClient} object. * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor, * on which you set the metadata for the RemoteControlClient instance. Once all the information diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp index 84028b7..d21b442 100644 --- a/media/jni/android_media_MediaScanner.cpp +++ b/media/jni/android_media_MediaScanner.cpp @@ -351,7 +351,7 @@ android_media_MediaScanner_extractAlbumArt( if (!data) { return NULL; } - long len = *((long*)data); + jsize len = *((uint32_t*)data); jbyteArray array = env->NewByteArray(len); if (array != NULL) { diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index a68ad2f..97051ff 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -22,21 +22,6 @@ android:id="@+id/task_view_thumbnail" android:layout_width="match_parent" android:layout_height="match_parent" /> - <com.android.systemui.recents.views.TaskInfoView - android:id="@+id/task_view_info_pane" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="invisible" - android:background="@color/recents_task_bar_default_background_color"> - <Button - android:id="@+id/task_view_app_info_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="20dp" - android:layout_marginEnd="20dp" - android:layout_gravity="top|center_horizontal" - android:text="@string/recents_app_info_button_label" /> - </com.android.systemui.recents.views.TaskInfoView> <com.android.systemui.recents.views.TaskBarView android:id="@+id/task_view_bar" android:layout_width="match_parent" diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 79545b3..fcbd0f4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -31,8 +31,6 @@ public class Constants { public static final boolean EnableTaskStackClipping = false; // Enables the use of theme colors as the task bar background public static final boolean EnableTaskBarThemeColors = true; - // Enables the info pane on long-pressing the task - public static final boolean EnableInfoPane = false; // Enables app-info pane on long-pressing the icon public static final boolean EnableDevAppInfoOnLongPress = true; // Enables the search bar layout diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index bae8a99..de696db 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -394,16 +394,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView public void onBackPressed() { boolean interceptedByInfoPanelClose = false; - // Try and return from any open info panes - if (Constants.DebugFlags.App.EnableInfoPane) { - interceptedByInfoPanelClose = mRecentsView.closeOpenInfoPanes(); - } - - // If we haven't been intercepted already, then unfilter any stacks - if (!interceptedByInfoPanelClose) { - if (!mRecentsView.unfilterFilteredStacks()) { - super.onBackPressed(); - } + // Unfilter any stacks + if (!mRecentsView.unfilterFilteredStacks()) { + super.onBackPressed(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index c63e688..cad54fa 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -301,24 +301,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV return insets.consumeSystemWindowInsets(false, false, false, true); } - /** Closes any open info panes */ - public boolean closeOpenInfoPanes() { - if (mBSP != null) { - // Get the first stack view - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); - if (child instanceof TaskStackView) { - TaskStackView stackView = (TaskStackView) child; - if (stackView.closeOpenInfoPanes()) { - return true; - } - } - } - } - return false; - } - /** Unfilters any filtered stacks */ public boolean unfilterFilteredStacks() { if (mBSP != null) { @@ -346,9 +328,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV mCb.onTaskLaunching(); } - // Close any open info panes - closeOpenInfoPanes(); - final Runnable launchRunnable = new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java deleted file mode 100644 index 7b6572b..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java +++ /dev/null @@ -1,185 +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 com.android.systemui.recents.views; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Canvas; -import android.graphics.Path; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.drawable.RippleDrawable; -import android.util.AttributeSet; -import android.widget.Button; -import android.widget.FrameLayout; -import com.android.systemui.R; -import com.android.systemui.recents.Constants; -import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.Utilities; -import com.android.systemui.recents.model.Task; - - -/* The task info view */ -class TaskInfoView extends FrameLayout { - - Button mAppInfoButton; - - // Circular clip animation - boolean mCircularClipEnabled; - Path mClipPath = new Path(); - float mClipRadius; - float mMaxClipRadius; - Point mClipOrigin = new Point(); - ObjectAnimator mCircularClipAnimator; - - public TaskInfoView(Context context) { - this(context, null); - } - - public TaskInfoView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public TaskInfoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @Override - protected void onFinishInflate() { - // Initialize the buttons on the info panel - mAppInfoButton = (Button) findViewById(R.id.task_view_app_info_button); - } - - /** Updates the positions of each of the items to fit in the rect specified */ - void updateContents(Rect visibleRect) { - // Offset the app info button - mAppInfoButton.setTranslationY(visibleRect.top + - (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2); - } - - /** Sets the circular clip radius on this panel */ - public void setCircularClipRadius(float r) { - mClipRadius = r; - invalidate(); - } - - /** Gets the circular clip radius on this panel */ - public float getCircularClipRadius() { - return mClipRadius; - } - - /** Animates the circular clip radius on the icon */ - void animateCircularClip(Point o, float fromRadius, float toRadius, - final Runnable postRunnable, boolean animateInContent) { - if (mCircularClipAnimator != null) { - mCircularClipAnimator.cancel(); - } - - // Calculate the max clip radius to each of the corners - int w = getMeasuredWidth() - o.x; - int h = getMeasuredHeight() - o.y; - // origin to tl, tr, br, bl - mMaxClipRadius = (int) Math.ceil(Math.sqrt(o.x * o.x + o.y * o.y)); - mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + o.y * o.y))); - mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(w * w + h * h))); - mMaxClipRadius = (int) Math.max(mMaxClipRadius, Math.ceil(Math.sqrt(o.x * o.x + h * h))); - - mClipOrigin.set(o.x, o.y); - mClipRadius = fromRadius; - int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius); - mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius); - mCircularClipAnimator.setDuration(duration); - mCircularClipAnimator.setInterpolator( - RecentsConfiguration.getInstance().defaultBezierInterpolator); - mCircularClipAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mCircularClipEnabled = false; - if (postRunnable != null) { - postRunnable.run(); - } - } - }); - mCircularClipAnimator.start(); - mCircularClipEnabled = true; - - if (animateInContent) { - animateAppInfoButtonIn(duration); - } - } - - /** Cancels the circular clip animation. */ - void cancelCircularClipAnimation() { - if (mCircularClipAnimator != null) { - mCircularClipAnimator.cancel(); - } - } - - void animateAppInfoButtonIn(int duration) { - mAppInfoButton.setScaleX(0.75f); - mAppInfoButton.setScaleY(0.75f); - mAppInfoButton.animate() - .scaleX(1f) - .scaleY(1f) - .setDuration(duration) - .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator) - .withLayer() - .start(); - } - - /** Binds the info view to the task */ - void rebindToTask(Task t, boolean animate) { - RecentsConfiguration configuration = RecentsConfiguration.getInstance(); - if (Constants.DebugFlags.App.EnableTaskBarThemeColors && t.colorPrimary != 0) { - setBackgroundColor(t.colorPrimary); - // Workaround: The button currently doesn't support setting a custom background tint - // not defined in the theme. Just lower the alpha on the button to make it blend more - // into the background. - if (mAppInfoButton.getBackground() instanceof RippleDrawable) { - RippleDrawable d = (RippleDrawable) mAppInfoButton.getBackground(); - if (d != null) { - d.setAlpha(96); - } - } - } else { - setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor); - } - } - - @Override - public void draw(Canvas canvas) { - int saveCount = 0; - if (mCircularClipEnabled) { - saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); - mClipPath.reset(); - mClipPath.addCircle(mClipOrigin.x, mClipOrigin.y, mClipRadius * mMaxClipRadius, - Path.Direction.CW); - canvas.clipPath(mClipPath); - } - super.draw(canvas); - if (mCircularClipEnabled) { - canvas.restoreToCount(saveCount); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 37c3c35..0687222 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -54,7 +54,7 @@ import java.util.Set; /* The visual representation of a task stack view */ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks, TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>, - View.OnClickListener, View.OnLongClickListener, RecentsPackageMonitor.PackageCallbacks { + View.OnClickListener, RecentsPackageMonitor.PackageCallbacks { /** The TaskView callbacks */ interface TaskStackViewCallbacks { @@ -79,7 +79,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int mMinScroll; int mMaxScroll; int mStashedScroll; - int mLastInfoPaneStackScroll; int mFocusedTaskIndex = -1; OverScroller mScroller; ObjectAnimator mScrollAnimator; @@ -290,17 +289,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void setStackScroll(int value) { mStackScroll = value; requestSynchronizeStackViewsWithModel(); - - // Close any open info panes if the user has scrolled away from them - boolean isAnimatingScroll = (mScrollAnimator != null && mScrollAnimator.isRunning()); - if (mLastInfoPaneStackScroll > -1 && !isAnimatingScroll) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - if (Math.abs(mStackScroll - mLastInfoPaneStackScroll) > - config.taskStackScrollDismissInfoPaneDistance) { - // Close any open info panes - closeOpenInfoPanes(); - } - } } /** Sets the current stack scroll without synchronizing the stack view with the model */ public void setStackScrollRaw(int value) { @@ -455,21 +443,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - /** Closes any open info panes. */ - boolean closeOpenInfoPanes() { - if (!Constants.DebugFlags.App.EnableInfoPane) return false; - - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - TaskView tv = (TaskView) getChildAt(i); - if (tv.isInfoPaneVisible()) { - tv.hideInfoPane(); - return true; - } - } - return false; - } - /** Focuses the task at the specified index in the stack */ void focusTask(int taskIndex, boolean scrollToNewPosition) { Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "" + taskIndex); @@ -949,9 +922,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks, Task filteredTask) { - // Close any open info panes - closeOpenInfoPanes(); - // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); @@ -976,9 +946,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) { - // Close any open info panes - closeOpenInfoPanes(); - // Calculate the current task transforms final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curTasks, getStackScroll(), null, true); @@ -1058,9 +1025,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Set the callbacks and listeners for this new view tv.setOnClickListener(this); - if (Constants.DebugFlags.App.EnableInfoPane) { - tv.setOnLongClickListener(this); - } tv.setCallbacks(this); } else { attachViewToParent(tv, insertIndex, tv.getLayoutParams()); @@ -1094,17 +1058,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override - public void onTaskInfoPanelShown(TaskView tv) { - // Do nothing - } - - @Override - public void onTaskInfoPanelHidden(TaskView tv) { - // Unset the saved scroll - mLastInfoPaneStackScroll = -1; - } - - @Override public void onTaskAppInfoClicked(TaskView tv) { if (mCb != null) { mCb.onTaskAppInfoLaunched(tv.getTask()); @@ -1129,52 +1082,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]", task + " cb: " + mCb); - // Close any open info panes if the user taps on another task - if (closeOpenInfoPanes()) { - return; - } - if (mCb != null) { mCb.onTaskLaunched(this, tv, mStack, task); } } - @Override - public boolean onLongClick(View v) { - if (!Constants.DebugFlags.App.EnableInfoPane) return false; - - TaskView tv = (TaskView) v; - - // Close any other task info panels if we launch another info pane - closeOpenInfoPanes(); - - // Scroll the task view so that it is maximally visible - float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); - int taskIndex = mStack.indexOfTask(tv.getTask()); - int curScroll = getStackScroll(); - int newScroll = (int) Math.max(mMinScroll, Math.min(mMaxScroll, taskIndex * overlapHeight)); - TaskViewTransform transform = getStackTransform(taskIndex, curScroll); - Rect nonOverlapRect = new Rect(transform.rect); - if (taskIndex < (mStack.getTaskCount() - 1)) { - nonOverlapRect.bottom = nonOverlapRect.top + (int) overlapHeight; - } - - // XXX: Use HW Layers - if (transform.t < 0f) { - animateScroll(curScroll, newScroll, null); - } else if (nonOverlapRect.bottom > mStackRectSansPeek.bottom) { - // Check if we are out of bounds, if so, just scroll it in such that the bottom of the - // task view is visible - newScroll = curScroll - (mStackRectSansPeek.bottom - nonOverlapRect.bottom); - animateScroll(curScroll, newScroll, null); - } - mLastInfoPaneStackScroll = newScroll; - - // Show the info pane for this task view - tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight)); - return true; - } - /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ @Override @@ -1550,13 +1462,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } - // If the info panel is currently showing on this view, then we need to dismiss it - if (Constants.DebugFlags.App.EnableInfoPane) { - TaskView tv = (TaskView) v; - if (tv.isInfoPaneVisible()) { - tv.hideInfoPane(); - } - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 46af4c1..780f274 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -44,8 +44,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On /** The TaskView callbacks */ interface TaskViewCallbacks { public void onTaskIconClicked(TaskView tv); - public void onTaskInfoPanelShown(TaskView tv); - public void onTaskInfoPanelHidden(TaskView tv); public void onTaskAppInfoClicked(TaskView tv); public void onTaskDismissed(TaskView tv); @@ -58,14 +56,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On Task mTask; boolean mTaskDataLoaded; - boolean mTaskInfoPaneVisible; boolean mIsFocused; Point mLastTouchDown = new Point(); Path mRoundedRectClipPath = new Path(); TaskThumbnailView mThumbnailView; TaskBarView mBarView; - TaskInfoView mInfoView; TaskViewCallbacks mCb; @@ -94,7 +90,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On // Bind the views mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail); mBarView = (TaskBarView) findViewById(R.id.task_view_bar); - mInfoView = (TaskInfoView) findViewById(R.id.task_view_info_pane); if (mTaskDataLoaded) { onTaskDataLoaded(false); @@ -280,63 +275,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On return outRect; } - /** Returns whether this task has an info pane visible */ - boolean isInfoPaneVisible() { - return mTaskInfoPaneVisible; - } - - /** Shows the info pane if it is not visible. */ - void showInfoPane(Rect taskVisibleRect) { - if (mTaskInfoPaneVisible) return; - - // Remove the bar view from the visible rect and update the info pane contents - taskVisibleRect.top += mBarView.getMeasuredHeight(); - mInfoView.updateContents(taskVisibleRect); - - // Show the info pane and animate it into view - mInfoView.setVisibility(View.VISIBLE); - mInfoView.animateCircularClip(mLastTouchDown, 0f, 1f, null, true); - mInfoView.setOnClickListener(this); - mTaskInfoPaneVisible = true; - - // Notify any callbacks - if (mCb != null) { - mCb.onTaskInfoPanelShown(this); - } - } - - /** Hides the info pane if it is visible. */ - void hideInfoPane() { - if (!mTaskInfoPaneVisible) return; - RecentsConfiguration config = RecentsConfiguration.getInstance(); - - // Cancel any circular clip animation - mInfoView.cancelCircularClipAnimation(); - - // Animate the info pane out - mInfoView.animate() - .alpha(0f) - .setDuration(config.taskViewInfoPaneAnimDuration) - .setInterpolator(config.defaultBezierInterpolator) - .withLayer() - .withEndAction(new Runnable() { - @Override - public void run() { - mInfoView.setVisibility(View.INVISIBLE); - mInfoView.setOnClickListener(null); - - mInfoView.setAlpha(1f); - } - }) - .start(); - mTaskInfoPaneVisible = false; - - // Notify any callbacks - if (mCb != null) { - mCb.onTaskInfoPanelHidden(this); - } - } - /** Enable the hw layers on this task view */ void enableHwLayers() { mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null); @@ -408,11 +346,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On @Override public void onTaskDataLoaded(boolean reloadingTaskData) { - if (mThumbnailView != null && mBarView != null && mInfoView != null) { + if (mThumbnailView != null && mBarView != null) { // Bind each of the views to the new task data mThumbnailView.rebindToTask(mTask, reloadingTaskData); mBarView.rebindToTask(mTask, reloadingTaskData); - mInfoView.rebindToTask(mTask, reloadingTaskData); // Rebind any listeners mBarView.mApplicationIcon.setOnClickListener(this); mBarView.mDismissButton.setOnClickListener(this); @@ -424,16 +361,13 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On mBarView.mApplicationIcon.setOnLongClickListener(this); } } - if (Constants.DebugFlags.App.EnableInfoPane) { - mInfoView.mAppInfoButton.setOnClickListener(this); - } } mTaskDataLoaded = true; } @Override public void onTaskDataUnloaded() { - if (mThumbnailView != null && mBarView != null && mInfoView != null) { + if (mThumbnailView != null && mBarView != null) { // Unbind each of the views from the task data and remove the task callback mTask.setCallbacks(null); mThumbnailView.unbindFromTask(); @@ -444,18 +378,13 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) { mBarView.mApplicationIcon.setOnLongClickListener(null); } - if (Constants.DebugFlags.App.EnableInfoPane) { - mInfoView.mAppInfoButton.setOnClickListener(null); - } } mTaskDataLoaded = false; } @Override public void onClick(View v) { - if (v == mInfoView) { - hideInfoPane(); - } else if (v == mBarView.mApplicationIcon) { + if (v == mBarView.mApplicationIcon) { mCb.onTaskIconClicked(this); } else if (v == mBarView.mDismissButton) { // Animate out the view and call the callback @@ -466,8 +395,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On mCb.onTaskDismissed(tv); } }); - } else if (v == mInfoView.mAppInfoButton) { - mCb.onTaskAppInfoClicked(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index dc3d92a..ac16164 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -45,7 +45,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView = new PathInterpolator(0.6f, 0, 0.5f, 1); private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR = new PathInterpolator(0, 0, 0.5f, 1); - private final int mMaxNotificationHeight; private boolean mDimmed; @@ -81,8 +80,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); - mMaxNotificationHeight = getResources().getDimensionPixelSize( - R.dimen.notification_max_height); setClipChildren(false); setClipToPadding(false); } @@ -92,7 +89,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView super.onFinishInflate(); mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal); mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed); - updateBackgroundResource(); + updateBackgroundResources(); } private final Runnable mTapTimeoutRunnable = new Runnable() { @@ -218,9 +215,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView if (mDimmed != dimmed) { mDimmed = dimmed; if (fade) { - fadeBackgroundResource(); + fadeBackground(); } else { - updateBackgroundResource(); + updateBackground(); } } } @@ -236,14 +233,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBgTint = bgTint; mDimmedBgResId = dimmedBgResId; mDimmedBgTint = dimmedTint; - updateBackgroundResource(); + updateBackgroundResources(); } public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) { setBackgroundResourceIds(bgResId, 0, dimmedBgResId, 0); } - private void fadeBackgroundResource() { + private void fadeBackground() { if (mDimmed) { mBackgroundDimmed.setVisibility(View.VISIBLE); } else { @@ -259,7 +256,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundAnimator.removeAllListeners(); mBackgroundAnimator.cancel(); if (duration <= 0) { - updateBackgroundResource(); + updateBackground(); return; } } @@ -282,38 +279,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundAnimator.start(); } - private void updateBackgroundResource() { + private void updateBackground() { if (mDimmed) { mBackgroundDimmed.setVisibility(View.VISIBLE); - mBackgroundDimmed.setCustomBackground(mDimmedBgResId, mDimmedBgTint); mBackgroundNormal.setVisibility(View.INVISIBLE); } else { mBackgroundDimmed.setVisibility(View.INVISIBLE); mBackgroundNormal.setVisibility(View.VISIBLE); - mBackgroundNormal.setCustomBackground(mBgResId, mBgTint); mBackgroundNormal.setAlpha(1f); } } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int newHeightSpec = MeasureSpec.makeMeasureSpec(mMaxNotificationHeight, - MeasureSpec.AT_MOST); - int maxChildHeight = 0; - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); - if (child != mBackgroundDimmed && child != mBackgroundNormal) { - child.measure(widthMeasureSpec, newHeightSpec); - int childHeight = child.getMeasuredHeight(); - maxChildHeight = Math.max(maxChildHeight, childHeight); - } - } - newHeightSpec = MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY); - mBackgroundDimmed.measure(widthMeasureSpec, newHeightSpec); - mBackgroundNormal.measure(widthMeasureSpec, newHeightSpec); - int width = MeasureSpec.getSize(widthMeasureSpec); - setMeasuredDimension(width, maxChildHeight); + private void updateBackgroundResources() { + mBackgroundDimmed.setCustomBackground(mDimmedBgResId, mDimmedBgTint); + mBackgroundNormal.setCustomBackground(mBgResId, mBgTint); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index eb4e77a..e699dd9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -619,7 +619,6 @@ public abstract class BaseStatusBar extends SystemUI implements protected void hideRecents(boolean triggeredFromAltTab) { if (mRecents != null) { - sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS); mRecents.hideRecents(triggeredFromAltTab); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 8f92a4c..84005d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -258,11 +258,4 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public void notifyContentUpdated() { mPrivateLayout.notifyContentUpdated(); } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int newHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY); - mVetoButton.measure(widthMeasureSpec, newHeightSpec); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index 5cb1b78..eaaac10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -21,38 +21,77 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; +import com.android.systemui.R; + +import java.util.ArrayList; /** * An abstract view for expandable views. */ -public abstract class ExpandableView extends ViewGroup { +public abstract class ExpandableView extends FrameLayout { + + private final int mMaxNotificationHeight; private OnHeightChangedListener mOnHeightChangedListener; protected int mActualHeight; protected int mClipTopAmount; private boolean mActualHeightInitialized; + private ArrayList<View> mMatchParentViews = new ArrayList<View>(); public ExpandableView(Context context, AttributeSet attrs) { super(context, attrs); + mMaxNotificationHeight = getResources().getDimensionPixelSize( + R.dimen.notification_max_height); } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - for (int i = 0; i < getChildCount(); i++) { + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int ownMaxHeight = mMaxNotificationHeight; + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY; + boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST; + if (hasFixedHeight || isHeightLimited) { + int size = MeasureSpec.getSize(heightMeasureSpec); + ownMaxHeight = Math.min(ownMaxHeight, size); + } + int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST); + int maxChildHeight = 0; + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - int height = child.getMeasuredHeight(); - int width = child.getMeasuredWidth(); - int center = getWidth() / 2; - int childLeft = center - width / 2; - child.layout(childLeft, - 0, - childLeft + width, - height); + int childHeightSpec = newHeightSpec; + ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); + if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) { + if (layoutParams.height >= 0) { + // An actual height is set + childHeightSpec = layoutParams.height > ownMaxHeight + ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY) + : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY); + } + child.measure(widthMeasureSpec, childHeightSpec); + int childHeight = child.getMeasuredHeight(); + maxChildHeight = Math.max(maxChildHeight, childHeight); + } else { + mMatchParentViews.add(child); + } + } + int ownHeight = hasFixedHeight ? ownMaxHeight : maxChildHeight; + newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY); + for (View child : mMatchParentViews) { + child.measure(widthMeasureSpec, newHeightSpec); } + mMatchParentViews.clear(); + int width = MeasureSpec.getSize(widthMeasureSpec); + setMeasuredDimension(width, ownHeight); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); if (!mActualHeightInitialized && mActualHeight == 0) { - mActualHeight = getInitialHeight(); + setActualHeight(getInitialHeight()); } - mActualHeightInitialized = true; } protected int getInitialHeight() { @@ -87,6 +126,7 @@ public abstract class ExpandableView extends ViewGroup { } public void setActualHeight(int actualHeight) { + mActualHeightInitialized = true; setActualHeight(actualHeight, true); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java index e49ec64..3c080fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java @@ -31,7 +31,6 @@ public class NotificationBackgroundView extends View { private Drawable mBackground; private int mClipTopAmount; private int mActualHeight; - private boolean mActualHeightInitialized; public NotificationBackgroundView(Context context, AttributeSet attrs) { super(context, attrs); @@ -39,15 +38,6 @@ public class NotificationBackgroundView extends View { } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (!mActualHeightInitialized && mActualHeight == 0) { - mActualHeight = getHeight(); - } - mActualHeightInitialized = true; - } - - @Override protected void onDraw(Canvas canvas) { draw(canvas, mBackground); } diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java index 49e1072..bfbd60d 100644 --- a/policy/src/com/android/internal/policy/impl/BarController.java +++ b/policy/src/com/android/internal/policy/impl/BarController.java @@ -121,7 +121,7 @@ public class BarController { } } else { vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag); - vis = (vis & View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT); + vis = (vis & ~View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT); } } return vis; diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 168742f..4ab8a01 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -22,7 +22,6 @@ import android.app.AlarmManager; import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -40,7 +39,6 @@ import android.os.UserHandle; import android.os.WorkSource; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -104,13 +102,21 @@ class AlarmManagerService extends SystemService { int mBroadcastRefCount = 0; PowerManager.WakeLock mWakeLock; boolean mLastWakeLockUnimportantForLogging; + ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>(); ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); final AlarmHandler mHandler = new AlarmHandler(); ClockReceiver mClockReceiver; + InteractiveStateReceiver mInteractiveStateReceiver; private UninstallReceiver mUninstallReceiver; final ResultReceiver mResultReceiver = new ResultReceiver(); PendingIntent mTimeTickSender; PendingIntent mDateChangeSender; + boolean mInteractive = true; + long mNonInteractiveStartTime; + long mNonInteractiveTime; + long mLastAlarmDeliveryTime; + long mStartCurrentDelayTime; + long mNextNonWakeupDeliveryTime; class WakeupEvent { public long when; @@ -318,7 +324,11 @@ class AlarmManagerService extends SystemService { final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() { @Override public int compare(Alarm lhs, Alarm rhs) { - if (lhs.wakeup != rhs.wakeup) { + if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage())) + && lhs.wakeup != rhs.wakeup) { + // We want to put wakeup alarms before non-wakeup alarms, since they are + // the things that drive most activity in the alarm manager. However, + // alarms from the same package should always be ordered strictly by time. return lhs.wakeup ? -1 : 1; } if (lhs.whenElapsed < rhs.whenElapsed) { @@ -424,24 +434,21 @@ class AlarmManagerService extends SystemService { static final class InFlight extends Intent { final PendingIntent mPendingIntent; final WorkSource mWorkSource; - final Pair<String, ComponentName> mTarget; + final String mTag; final BroadcastStats mBroadcastStats; final FilterStats mFilterStats; final int mAlarmType; InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource, - int alarmType) { + int alarmType, String tag) { mPendingIntent = pendingIntent; mWorkSource = workSource; - Intent intent = pendingIntent.getIntent(); - mTarget = intent != null - ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent()) - : null; + mTag = tag; mBroadcastStats = service.getStatsLocked(pendingIntent); - FilterStats fs = mBroadcastStats.filterStats.get(mTarget); + FilterStats fs = mBroadcastStats.filterStats.get(mTag); if (fs == null) { - fs = new FilterStats(mBroadcastStats, mTarget); - mBroadcastStats.filterStats.put(mTarget, fs); + fs = new FilterStats(mBroadcastStats, mTag); + mBroadcastStats.filterStats.put(mTag, fs); } mFilterStats = fs; mAlarmType = alarmType; @@ -450,7 +457,7 @@ class AlarmManagerService extends SystemService { static final class FilterStats { final BroadcastStats mBroadcastStats; - final Pair<String, ComponentName> mTarget; + final String mTag; long aggregateTime; int count; @@ -458,9 +465,9 @@ class AlarmManagerService extends SystemService { long startTime; int nesting; - FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) { + FilterStats(BroadcastStats broadcastStats, String tag) { mBroadcastStats = broadcastStats; - mTarget = target; + mTag = tag; } } @@ -473,8 +480,7 @@ class AlarmManagerService extends SystemService { int numWakeup; long startTime; int nesting; - final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats - = new ArrayMap<Pair<String, ComponentName>, FilterStats>(); + final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>(); BroadcastStats(int uid, String packageName) { mUid = uid; @@ -484,7 +490,11 @@ class AlarmManagerService extends SystemService { final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats = new SparseArray<ArrayMap<String, BroadcastStats>>(); - + + int mNumDelayedAlarms = 0; + long mTotalDelayTime = 0; + long mMaxDelayTime = 0; + @Override public void onStart() { mNativeData = init(); @@ -511,6 +521,7 @@ class AlarmManagerService extends SystemService { mClockReceiver = new ClockReceiver(); mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); + mInteractiveStateReceiver = new InteractiveStateReceiver(); mUninstallReceiver = new UninstallReceiver(); if (mNativeData != 0) { @@ -735,13 +746,29 @@ class AlarmManagerService extends SystemService { pw.print("nowRTC="); pw.print(nowRTC); pw.print("="); pw.print(sdf.format(new Date(nowRTC))); - pw.print(" nowELAPSED="); pw.println(nowELAPSED); + pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw); + pw.println(); + if (!mInteractive) { + pw.print("Time since non-interactive: "); + TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw); + pw.println(); + pw.print("Max wakeup delay: "); + TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw); + pw.println(); + pw.print("Time since last dispatch: "); + TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw); + pw.println(); + pw.print("Next non-wakeup delivery time: "); + TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw); + pw.println(); + } long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED); long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED); - pw.print("Next alarm: "); pw.print(mNextNonWakeup); + pw.print("Next non-wakeup alarm: "); + TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC))); - pw.print("Next wakeup: "); pw.print(mNextWakeup); + pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); if (mAlarmBatches.size() > 0) { @@ -750,11 +777,27 @@ class AlarmManagerService extends SystemService { pw.println(mAlarmBatches.size()); for (Batch b : mAlarmBatches) { pw.print(b); pw.println(':'); - dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC); + dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf); } } pw.println(); + pw.print("Past-due non-wakeup alarms: "); + if (mPendingNonWakeupAlarms.size() > 0) { + pw.println(mPendingNonWakeupAlarms.size()); + dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf); + } else { + pw.println("(none)"); + } + pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms); + pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw); + pw.println(); + pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw); + pw.print(", max non-interactive time: "); + TimeUtils.formatDuration(mNonInteractiveTime, pw); + pw.println(); + + pw.println(); pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); pw.println(); @@ -811,13 +854,7 @@ class AlarmManagerService extends SystemService { pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid); pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName); pw.println(); - pw.print(" "); - if (fs.mTarget.first != null) { - pw.print(" act="); pw.print(fs.mTarget.first); - } - if (fs.mTarget.second != null) { - pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString()); - } + pw.print(" "); pw.print(fs.mTag); pw.println(); } } @@ -849,13 +886,8 @@ class AlarmManagerService extends SystemService { TimeUtils.formatDuration(fs.aggregateTime, pw); pw.print(" "); pw.print(fs.numWakeup); pw.print(" wakes " ); pw.print(fs.count); - pw.print(" alarms:"); - if (fs.mTarget.first != null) { - pw.print(" act="); pw.print(fs.mTarget.first); - } - if (fs.mTarget.second != null) { - pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString()); - } + pw.print(" alarms: "); + pw.print(fs.mTag); pw.println(); } } @@ -883,7 +915,7 @@ class AlarmManagerService extends SystemService { } } - private void logBatchesLocked() { + private void logBatchesLocked(SimpleDateFormat sdf) { ByteArrayOutputStream bs = new ByteArrayOutputStream(2048); PrintWriter pw = new PrintWriter(bs); final long nowRTC = System.currentTimeMillis(); @@ -892,7 +924,7 @@ class AlarmManagerService extends SystemService { for (int iz = 0; iz < NZ; iz++) { Batch bz = mAlarmBatches.get(iz); pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz); - dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC); + dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf); pw.flush(); Slog.v(TAG, bs.toString()); bs.reset(); @@ -910,7 +942,8 @@ class AlarmManagerService extends SystemService { lastTime = b.start; } else { Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order"); - logBatchesLocked(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + logBatchesLocked(sdf); return false; } } @@ -932,6 +965,7 @@ class AlarmManagerService extends SystemService { void rescheduleKernelAlarmsLocked() { // Schedule the next upcoming wakeup alarm. If there is a deliverable batch // prior to that which contains no wakeups, we schedule that as well. + long nextNonWakeup = 0; if (mAlarmBatches.size() > 0) { final Batch firstWakeup = findFirstWakeupBatchLocked(); final Batch firstBatch = mAlarmBatches.get(0); @@ -939,11 +973,19 @@ class AlarmManagerService extends SystemService { mNextWakeup = firstWakeup.start; setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); } - if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) { - mNextNonWakeup = firstBatch.start; - setLocked(ELAPSED_REALTIME, firstBatch.start); + if (firstBatch != firstWakeup) { + nextNonWakeup = firstBatch.start; + } + } + if (mPendingNonWakeupAlarms.size() > 0) { + if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) { + nextNonWakeup = mNextNonWakeupDeliveryTime; } } + if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) { + mNextNonWakeup = nextNonWakeup; + setLocked(ELAPSED_REALTIME, nextNonWakeup); + } } private void removeLocked(PendingIntent operation) { @@ -1003,6 +1045,32 @@ class AlarmManagerService extends SystemService { } } + void interactiveStateChangedLocked(boolean interactive) { + if (mInteractive != interactive) { + mInteractive = interactive; + final long nowELAPSED = SystemClock.elapsedRealtime(); + if (interactive) { + if (mPendingNonWakeupAlarms.size() > 0) { + final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; + mTotalDelayTime += thisDelayTime; + if (mMaxDelayTime < thisDelayTime) { + mMaxDelayTime = thisDelayTime; + } + deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED); + mPendingNonWakeupAlarms.clear(); + } + if (mNonInteractiveStartTime > 0) { + long dur = nowELAPSED - mNonInteractiveStartTime; + if (dur > mNonInteractiveTime) { + mNonInteractiveTime = dur; + } + } + } else { + mNonInteractiveStartTime = nowELAPSED; + } + } + } + boolean lookForPackageLocked(String packageName) { for (int i = 0; i < mAlarmBatches.size(); i++) { Batch b = mAlarmBatches.get(i); @@ -1037,12 +1105,12 @@ class AlarmManagerService extends SystemService { } private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, - String prefix, String label, long now) { + String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) { for (int i=list.size()-1; i>=0; i--) { Alarm a = list.get(i); pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); pw.print(": "); pw.println(a); - a.dump(pw, prefix + " ", now); + a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); } } @@ -1059,14 +1127,13 @@ class AlarmManagerService extends SystemService { } private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, - String prefix, long nowELAPSED, long nowRTC) { + String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) { for (int i=list.size()-1; i>=0; i--) { Alarm a = list.get(i); final String label = labelForType(a.type); - long now = (a.type <= RTC) ? nowRTC : nowELAPSED; pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); pw.print(": "); pw.println(a); - a.dump(pw, prefix + " ", now); + a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); } } @@ -1077,8 +1144,9 @@ class AlarmManagerService extends SystemService { private native int setKernelTime(long nativeData, long millis); private native int setKernelTimezone(long nativeData, int minuteswest); - void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, + boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, final long nowRTC) { + boolean hasWakeup = false; // batches are temporally sorted, so we need only pull from the // start of the list until we either empty it or hit a batch // that is not yet deliverable @@ -1113,8 +1181,14 @@ class AlarmManagerService extends SystemService { maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval), alarm.repeatInterval, alarm.operation, batch.standalone, true, alarm.workSource); - } + // For now we count this as a wakeup alarm, meaning it needs to be + // delivered immediately. In the future we should change this, but + // that required delaying when we reschedule the repeat...! + hasWakeup = false; + } else if (alarm.wakeup) { + hasWakeup = true; + } } } @@ -1125,6 +1199,8 @@ class AlarmManagerService extends SystemService { Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i)); } } + + return hasWakeup; } /** @@ -1147,15 +1223,16 @@ class AlarmManagerService extends SystemService { private static class Alarm { public final int type; public final boolean wakeup; + public final PendingIntent operation; + public final String tag; + public final WorkSource workSource; public int count; public long when; public long windowLength; public long whenElapsed; // 'when' in the elapsed time base public long maxWhen; // also in the elapsed time base public long repeatInterval; - public PendingIntent operation; - public WorkSource workSource; - + public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen, long _interval, PendingIntent _op, WorkSource _ws) { type = _type; @@ -1167,12 +1244,17 @@ class AlarmManagerService extends SystemService { maxWhen = _maxWhen; repeatInterval = _interval; operation = _op; + tag = makeTag(_op, _type); workSource = _ws; } + public static String makeTag(PendingIntent pi, int type) { + return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP + ? "*walarm*:" : "*alarm*:"); + } + @Override - public String toString() - { + public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("Alarm{"); sb.append(Integer.toHexString(System.identityHashCode(this))); @@ -1186,11 +1268,20 @@ class AlarmManagerService extends SystemService { return sb.toString(); } - public void dump(PrintWriter pw, String prefix, long now) { + public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED, + SimpleDateFormat sdf) { + final boolean isRtc = (type == RTC || type == RTC_WAKEUP); + pw.print(prefix); pw.print("tag="); pw.println(tag); pw.print(prefix); pw.print("type="); pw.print(type); - pw.print(" whenElapsed="); pw.print(whenElapsed); - pw.print(" when="); TimeUtils.formatDuration(when, now, pw); - pw.print(" window="); pw.print(windowLength); + pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed, + nowELAPSED, pw); + if (isRtc) { + pw.print(" when="); pw.print(sdf.format(new Date(when))); + } else { + pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw); + } + pw.println(); + pw.print(prefix); pw.print("window="); pw.print(windowLength); pw.print(" repeatInterval="); pw.print(repeatInterval); pw.print(" count="); pw.println(count); pw.print(prefix); pw.print("operation="); pw.println(operation); @@ -1216,6 +1307,102 @@ class AlarmManagerService extends SystemService { } } + long currentNonWakeupFuzzLocked(long nowELAPSED) { + long timeSinceOn = nowELAPSED - mNonInteractiveStartTime; + if (timeSinceOn < 5*60*1000) { + // If the screen has been off for 5 minutes, only delay by at most two minutes. + return 2*60*1000; + } else if (timeSinceOn < 30*60*1000) { + // If the screen has been off for 30 minutes, only delay by at most 15 minutes. + return 15*60*1000; + } else { + // Otherwise, we will delay by at most an hour. + return 60*60*1000; + } + } + + boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) { + if (mInteractive) { + return false; + } + if (mLastAlarmDeliveryTime <= 0) { + return false; + } + if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) { + // This is just a little paranoia, if somehow we have pending non-wakeup alarms + // and the next delivery time is in the past, then just deliver them all. This + // avoids bugs where we get stuck in a loop trying to poll for alarms. + return false; + } + long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime; + return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED); + } + + void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) { + mLastAlarmDeliveryTime = nowELAPSED; + for (int i=0; i<triggerList.size(); i++) { + Alarm alarm = triggerList.get(i); + try { + if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); + alarm.operation.send(getContext(), 0, + mBackgroundIntent.putExtra( + Intent.EXTRA_ALARM_COUNT, alarm.count), + mResultReceiver, mHandler); + + // we have an active broadcast so stay awake. + if (mBroadcastRefCount == 0) { + setWakelockWorkSource(alarm.operation, alarm.workSource, + alarm.type, alarm.tag, true); + mWakeLock.acquire(); + } + final InFlight inflight = new InFlight(AlarmManagerService.this, + alarm.operation, alarm.workSource, alarm.type, alarm.tag); + mInFlight.add(inflight); + mBroadcastRefCount++; + + final BroadcastStats bs = inflight.mBroadcastStats; + bs.count++; + if (bs.nesting == 0) { + bs.nesting = 1; + bs.startTime = nowELAPSED; + } else { + bs.nesting++; + } + final FilterStats fs = inflight.mFilterStats; + fs.count++; + if (fs.nesting == 0) { + fs.nesting = 1; + fs.startTime = nowELAPSED; + } else { + fs.nesting++; + } + if (alarm.type == ELAPSED_REALTIME_WAKEUP + || alarm.type == RTC_WAKEUP) { + bs.numWakeup++; + fs.numWakeup++; + if (alarm.workSource != null && alarm.workSource.size() > 0) { + for (int wi=0; wi<alarm.workSource.size(); wi++) { + ActivityManagerNative.noteWakeupAlarm( + alarm.operation, alarm.workSource.get(wi), + alarm.workSource.getName(wi)); + } + } else { + ActivityManagerNative.noteWakeupAlarm( + alarm.operation, -1, null); + } + } + } catch (PendingIntent.CanceledException e) { + if (alarm.repeatInterval > 0) { + // This IntentSender is no longer valid, but this + // is a repeating alarm, so toss the hoser. + removeImpl(alarm.operation); + } + } catch (RuntimeException e) { + Slog.w(TAG, "Failure sending alarm.", e); + } + } + } + private class AlarmThread extends Thread { public AlarmThread() @@ -1269,70 +1456,35 @@ class AlarmManagerService extends SystemService { } } - triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); - rescheduleKernelAlarmsLocked(); - - // now deliver the alarm intents - for (int i=0; i<triggerList.size(); i++) { - Alarm alarm = triggerList.get(i); - try { - if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); - alarm.operation.send(getContext(), 0, - mBackgroundIntent.putExtra( - Intent.EXTRA_ALARM_COUNT, alarm.count), - mResultReceiver, mHandler); - - // we have an active broadcast so stay awake. - if (mBroadcastRefCount == 0) { - setWakelockWorkSource(alarm.operation, alarm.workSource, - alarm.type, true); - mWakeLock.acquire(); - } - final InFlight inflight = new InFlight(AlarmManagerService.this, - alarm.operation, alarm.workSource, alarm.type); - mInFlight.add(inflight); - mBroadcastRefCount++; - - final BroadcastStats bs = inflight.mBroadcastStats; - bs.count++; - if (bs.nesting == 0) { - bs.nesting = 1; - bs.startTime = nowELAPSED; - } else { - bs.nesting++; - } - final FilterStats fs = inflight.mFilterStats; - fs.count++; - if (fs.nesting == 0) { - fs.nesting = 1; - fs.startTime = nowELAPSED; - } else { - fs.nesting++; - } - if (alarm.type == ELAPSED_REALTIME_WAKEUP - || alarm.type == RTC_WAKEUP) { - bs.numWakeup++; - fs.numWakeup++; - if (alarm.workSource != null && alarm.workSource.size() > 0) { - for (int wi=0; wi<alarm.workSource.size(); wi++) { - ActivityManagerNative.noteWakeupAlarm( - alarm.operation, alarm.workSource.get(wi), - alarm.workSource.getName(wi)); - } - } else { - ActivityManagerNative.noteWakeupAlarm( - alarm.operation, -1, null); - } - } - } catch (PendingIntent.CanceledException e) { - if (alarm.repeatInterval > 0) { - // This IntentSender is no longer valid, but this - // is a repeating alarm, so toss the hoser. - removeImpl(alarm.operation); + boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); + if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { + // if there are no wakeup alarms and the screen is off, we can + // delay what we have so far until the future. + if (mPendingNonWakeupAlarms.size() == 0) { + mStartCurrentDelayTime = nowELAPSED; + mNextNonWakeupDeliveryTime = nowELAPSED + + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2); + } + mPendingNonWakeupAlarms.addAll(triggerList); + mNumDelayedAlarms += triggerList.size(); + rescheduleKernelAlarmsLocked(); + } else { + // now deliver the alarm intents; if there are pending non-wakeup + // alarms, we need to merge them in to the list. note we don't + // just deliver them first because we generally want non-wakeup + // alarms delivered after wakeup alarms. + rescheduleKernelAlarmsLocked(); + if (mPendingNonWakeupAlarms.size() > 0) { + triggerList.addAll(mPendingNonWakeupAlarms); + Collections.sort(triggerList, mAlarmDispatchComparator); + final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; + mTotalDelayTime += thisDelayTime; + if (mMaxDelayTime < thisDelayTime) { + mMaxDelayTime = thisDelayTime; } - } catch (RuntimeException e) { - Slog.w(TAG, "Failure sending alarm.", e); + mPendingNonWakeupAlarms.clear(); } + deliverAlarmsLocked(triggerList, nowELAPSED); } } } @@ -1344,14 +1496,13 @@ class AlarmManagerService extends SystemService { * @param pi PendingIntent to attribute blame to if ws is null. * @param ws WorkSource to attribute blame. */ - void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, boolean first) { + void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag, + boolean first) { try { final boolean unimportant = pi == mTimeTickSender; mWakeLock.setUnimportantForLogging(unimportant); if (first || mLastWakeLockUnimportantForLogging) { - mWakeLock.setHistoryTag(pi.getTag( - type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP - ? "*walarm*:" : "*alarm*:")); + mWakeLock.setHistoryTag(tag); } else { mWakeLock.setHistoryTag(null); } @@ -1462,6 +1613,23 @@ class AlarmManagerService extends SystemService { } } + class InteractiveStateReceiver extends BroadcastReceiver { + public InteractiveStateReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + getContext().registerReceiver(this, filter); + } + + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mLock) { + interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); + } + } + } + class UninstallReceiver extends BroadcastReceiver { public UninstallReceiver() { IntentFilter filter = new IntentFilter(); @@ -1589,7 +1757,7 @@ class AlarmManagerService extends SystemService { if (mInFlight.size() > 0) { InFlight inFlight = mInFlight.get(0); setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource, - inFlight.mAlarmType, false); + inFlight.mAlarmType, inFlight.mTag, false); } else { // should never happen mLog.w("Alarm wakelock still held but sent queue empty"); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index cc132be..af53fef 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -398,7 +398,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * used internally when registering NetworkFactories - * obj = Messenger + * obj = NetworkFactoryInfo */ private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; @@ -434,6 +434,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_RELEASE_NETWORK_REQUEST = 22; + /** + * used internally when registering NetworkFactories + * obj = Messenger + */ + private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23; + + /** Handler used for internal events. */ final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -2889,6 +2896,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } + pw.println("NetworkFactories for:"); + pw.increaseIndent(); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + pw.println(nfi.name); + } + pw.decreaseIndent(); + pw.println(); + NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId); pw.print("Active default network: "); if (defaultNai == null) { @@ -2983,6 +2998,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (nai == null) { loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED"); } else { + if (VDBG) log("Update of Linkproperties for " + nai.name()); LinkProperties oldLp = nai.linkProperties; nai.linkProperties = (LinkProperties)msg.obj; updateLinkProperties(nai, oldLp); @@ -3096,18 +3112,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleAsyncChannelHalfConnect(Message msg) { AsyncChannel ac = (AsyncChannel) msg.obj; - if (mNetworkFactories.contains(ac)) { + if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); // A network factory has connected. Send it all current NetworkRequests. for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.isRequest == false) continue; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, (nai != null ? nai.currentScore : 0), 0, nri.request); } } else { loge("Error connecting NetworkFactory"); - mNetworkFactories.remove(ac); + mNetworkFactoryInfos.remove(msg.obj); } } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { @@ -3214,8 +3231,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetworkRequests.put(nri.request, nri); if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); - for (AsyncChannel ac : mNetworkFactories) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); } } } @@ -3236,8 +3253,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (nri.isRequest) { - for (AsyncChannel factory : mNetworkFactories) { - factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); } if (affectedNetwork != null) { @@ -3356,7 +3373,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } case EVENT_REGISTER_NETWORK_FACTORY: { - handleRegisterNetworkFactory((Messenger)msg.obj); + handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj); + break; + } + case EVENT_UNREGISTER_NETWORK_FACTORY: { + handleUnregisterNetworkFactory((Messenger)msg.obj); break; } case EVENT_REGISTER_NETWORK_AGENT: { @@ -5222,10 +5243,22 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); } - private final ArrayList<AsyncChannel> mNetworkFactories = new ArrayList<AsyncChannel>(); + private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = + new HashMap<Messenger, NetworkFactoryInfo>(); private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<NetworkRequest, NetworkRequestInfo>(); + private static class NetworkFactoryInfo { + public final String name; + public final Messenger messenger; + public final AsyncChannel asyncChannel; + + public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) { + this.name = name; + this.messenger = messenger; + this.asyncChannel = asyncChannel; + } + } private class NetworkRequestInfo implements IBinder.DeathRecipient { static final boolean REQUEST = true; @@ -5263,6 +5296,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { request + ", " + mBinder + ")"); releaseNetworkRequest(request); } + + public String toString() { + return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" + + mPid + " for " + request; + } } @Override @@ -5326,24 +5364,31 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @Override - public void registerNetworkFactory(Messenger messenger) { + public void registerNetworkFactory(Messenger messenger, String name) { enforceConnectivityInternalPermission(); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); + NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel()); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); } - private void handleRegisterNetworkFactory(Messenger messenger) { - if (VDBG) log("Got NetworkFactory Messenger"); - AsyncChannel ac = new AsyncChannel(); - mNetworkFactories.add(ac); - ac.connect(mContext, mTrackerHandler, messenger); - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.isRequest) { - int score = 0; - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); - if (currentNetwork != null) score = currentNetwork.currentScore; - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); - } + private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { + if (VDBG) log("Got NetworkFactory Messenger for " + nfi.name); + mNetworkFactoryInfos.put(nfi.messenger, nfi); + nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger); + } + + @Override + public void unregisterNetworkFactory(Messenger messenger) { + enforceConnectivityInternalPermission(); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger)); + } + + private void handleUnregisterNetworkFactory(Messenger messenger) { + NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger); + if (nfi == null) { + if (VDBG) log("Failed to find Messenger in unregisterNetworkFactory"); + return; } + if (VDBG) log("unregisterNetworkFactory for " + nfi.name); } /** @@ -5535,8 +5580,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); - for (AsyncChannel ac : mNetworkFactories) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); } } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 50553ee..5cb2a8a 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -3439,7 +3439,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " mShowExplicitlyRequested=" + mShowExplicitlyRequested + " mShowForced=" + mShowForced + " mInputShown=" + mInputShown); - p.println(" mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn); + p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mScreenOn); } p.println(" "); diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java index c32beda..cd8c13f 100644 --- a/services/core/java/com/android/server/WiredAccessoryManager.java +++ b/services/core/java/com/android/server/WiredAccessoryManager.java @@ -264,7 +264,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { } else if (headset == BIT_USB_HEADSET_DGTL) { device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; } else if (headset == BIT_HDMI_AUDIO) { - device = AudioManager.DEVICE_OUT_AUX_DIGITAL; + device = AudioManager.DEVICE_OUT_HDMI; } else { Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); return; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7abc75f..7cd4ef8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13837,7 +13837,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) { - ProxyInfo proxy = intent.getParcelableExtra("proxy"); + ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO); mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy)); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1734a33..9569c0d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -63,7 +63,7 @@ import android.service.notification.INotificationListener; import android.service.notification.IConditionListener; import android.service.notification.IConditionProvider; import android.service.notification.NotificationListenerService; -import android.service.notification.NotificationOrderUpdate; +import android.service.notification.NotificationRankingUpdate; import android.service.notification.StatusBarNotification; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; @@ -1744,7 +1744,7 @@ public class NotificationManagerService extends SystemService { sendAccessibilityEvent(notification, pkg); } - mListeners.notifyPostedLocked(r.sbn); + mListeners.notifyPostedLocked(r.sbn, cloneNotificationListLocked()); } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); if (old != null && old.statusBarKey != null) { @@ -1755,7 +1755,7 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } - mListeners.notifyRemovedLocked(r.sbn); + mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked()); } // ATTENTION: in a future release we will bail out here // so that we do not play sounds, show lights, etc. for invalid @@ -2041,14 +2041,17 @@ public class NotificationManagerService extends SystemService { private void handleSendRankingUpdate() { synchronized (mNotificationList) { - final int N = mNotificationList.size(); - ArrayList<StatusBarNotification> sbns = - new ArrayList<StatusBarNotification>(N); - for (int i = 0; i < N; i++ ) { - sbns.add(mNotificationList.get(i).sbn); - } - mListeners.notifyOrderUpdateLocked(sbns); + mListeners.notifyRankingUpdateLocked(cloneNotificationListLocked()); + } + } + + private ArrayList<StatusBarNotification> cloneNotificationListLocked() { + final int N = mNotificationList.size(); + ArrayList<StatusBarNotification> sbns = new ArrayList<StatusBarNotification>(N); + for (int i = 0; i < N; i++) { + sbns.add(mNotificationList.get(i).sbn); } + return sbns; } private final class WorkerHandler extends Handler @@ -2136,7 +2139,7 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } r.statusBarKey = null; - mListeners.notifyRemovedLocked(r.sbn); + mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked()); } // sound @@ -2442,6 +2445,33 @@ public class NotificationManagerService extends SystemService { } } + /** + * Generates a NotificationRankingUpdate from 'sbns', considering only + * notifications visible to the given listener. + */ + private static NotificationRankingUpdate makeRankingUpdateForListener(ManagedServiceInfo info, + ArrayList<StatusBarNotification> sbns) { + int speedBumpIndex = -1; + ArrayList<String> keys = new ArrayList<String>(sbns.size()); + ArrayList<String> dndKeys = new ArrayList<String>(sbns.size()); + for (StatusBarNotification sbn: sbns) { + if (!info.enabledAndUserMatches(sbn.getUserId())) { + continue; + } + keys.add(sbn.getKey()); + if (sbn.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) { + dndKeys.add(sbn.getKey()); + } + if (speedBumpIndex == -1 && + sbn.getNotification().priority == Notification.PRIORITY_MIN) { + speedBumpIndex = keys.size() - 1; + } + } + String[] keysAr = keys.toArray(new String[keys.size()]); + String[] dndKeysAr = dndKeys.toArray(new String[dndKeys.size()]); + return new NotificationRankingUpdate(keysAr, dndKeysAr, speedBumpIndex); + } + public class NotificationListeners extends ManagedServices { public NotificationListeners() { @@ -2468,9 +2498,12 @@ public class NotificationManagerService extends SystemService { @Override public void onServiceAdded(ManagedServiceInfo info) { final INotificationListener listener = (INotificationListener) info.service; - final String[] keys = getActiveNotificationKeys(listener); + final ArrayList<StatusBarNotification> sbns; + synchronized (mNotificationList) { + sbns = cloneNotificationListLocked(); + } try { - listener.onListenerConnected(new NotificationOrderUpdate(keys)); + listener.onListenerConnected(makeRankingUpdateForListener(info, sbns)); } catch (RemoteException e) { // we tried } @@ -2479,44 +2512,47 @@ public class NotificationManagerService extends SystemService { /** * asynchronously notify all listeners about a new notification */ - public void notifyPostedLocked(StatusBarNotification sbn) { + public void notifyPostedLocked(StatusBarNotification sbn, + final ArrayList<StatusBarNotification> sbns) { // make a copy in case changes are made to the underlying Notification object final StatusBarNotification sbnClone = sbn.clone(); for (final ManagedServiceInfo info : mServices) { - if (info.isEnabledForCurrentProfiles()) { - final INotificationListener listener = (INotificationListener) info.service; - final String[] keys = getActiveNotificationKeys(listener); - if (keys.length > 0) { - mHandler.post(new Runnable() { - @Override - public void run() { - notifyPostedIfUserMatch(info, sbnClone, keys); - } - }); - } + if (!info.isEnabledForCurrentProfiles()) { + continue; } + final NotificationRankingUpdate update = makeRankingUpdateForListener(info, sbns); + if (update.getOrderedKeys().length == 0) { + continue; + } + mHandler.post(new Runnable() { + @Override + public void run() { + notifyPostedIfUserMatch(info, sbnClone, update); + } + }); } } /** * asynchronously notify all listeners about a removed notification */ - public void notifyRemovedLocked(StatusBarNotification sbn) { + public void notifyRemovedLocked(StatusBarNotification sbn, + final ArrayList<StatusBarNotification> sbns) { // make a copy in case changes are made to the underlying Notification object // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the // notification final StatusBarNotification sbnLight = sbn.cloneLight(); for (final ManagedServiceInfo info : mServices) { - if (info.isEnabledForCurrentProfiles()) { - final INotificationListener listener = (INotificationListener) info.service; - final String[] keys = getActiveNotificationKeys(listener); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyRemovedIfUserMatch(info, sbnLight, keys); - } - }); + if (!info.isEnabledForCurrentProfiles()) { + continue; } + mHandler.post(new Runnable() { + @Override + public void run() { + notifyRemovedIfUserMatch(info, sbnLight, + makeRankingUpdateForListener(info, sbns)); + } + }); } } @@ -2526,60 +2562,52 @@ public class NotificationManagerService extends SystemService { * must not rely on mutable members of these objects, such as the * {@link Notification}. */ - public void notifyOrderUpdateLocked(final ArrayList<StatusBarNotification> sbns) { + public void notifyRankingUpdateLocked(final ArrayList<StatusBarNotification> sbns) { for (final ManagedServiceInfo serviceInfo : mServices) { + if (!serviceInfo.isEnabledForCurrentProfiles()) { + continue; + } mHandler.post(new Runnable() { @Override public void run() { - notifyOrderUpdateIfUserMatch(serviceInfo, sbns); + notifyRankingUpdate(serviceInfo, + makeRankingUpdateForListener(serviceInfo, sbns)); } }); } } private void notifyPostedIfUserMatch(final ManagedServiceInfo info, - final StatusBarNotification sbn, String[] keys) { + final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { if (!info.enabledAndUserMatches(sbn.getUserId())) { return; } final INotificationListener listener = (INotificationListener)info.service; try { - listener.onNotificationPosted(sbn, new NotificationOrderUpdate(keys)); + listener.onNotificationPosted(sbn, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (posted): " + listener, ex); } } private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn, - String[] keys) { + NotificationRankingUpdate rankingUpdate) { if (!info.enabledAndUserMatches(sbn.getUserId())) { return; } - final INotificationListener listener = (INotificationListener)info.service; + final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationRemoved(sbn, new NotificationOrderUpdate(keys)); + listener.onNotificationRemoved(sbn, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (removed): " + listener, ex); } } - /** - * @param sbns an array of {@link StatusBarNotification}s to consider. This code - * must not rely on mutable members of these objects, such as the - * {@link Notification}. - */ - public void notifyOrderUpdateIfUserMatch(ManagedServiceInfo info, - ArrayList<StatusBarNotification> sbns) { - ArrayList<String> keys = new ArrayList<String>(sbns.size()); - for (StatusBarNotification sbn: sbns) { - if (info.enabledAndUserMatches(sbn.getUserId())) { - keys.add(sbn.getKey()); - } - } - final INotificationListener listener = (INotificationListener)info.service; + private void notifyRankingUpdate(ManagedServiceInfo info, + NotificationRankingUpdate rankingUpdate) { + final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationOrderUpdate( - new NotificationOrderUpdate(keys.toArray(new String[keys.size()]))); + listener.onNotificationRankingUpdate(rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 61b3a89..46c5482 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -11876,6 +11876,7 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(" cmd may be one of:"); pw.println(" l[ibraries]: list known shared libraries"); pw.println(" f[ibraries]: list device features"); + pw.println(" k[eysets]: print known keysets"); pw.println(" r[esolvers]: dump intent resolvers"); pw.println(" perm[issions]: dump permissions"); pw.println(" pref[erred]: print preferred package settings"); @@ -11886,8 +11887,8 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(" m[essages]: print collected runtime messages"); pw.println(" v[erifiers]: print package verifier info"); pw.println(" version: print database version info"); + pw.println(" write: write current settings now"); pw.println(" <package.name>: info about given package"); - pw.println(" k[eysets]: print known keysets"); return; } else if ("--checkin".equals(opt)) { checkin = true; @@ -11938,6 +11939,12 @@ public class PackageManagerService extends IPackageManager.Stub { dumpState.setDump(DumpState.DUMP_VERSION); } else if ("k".equals(cmd) || "keysets".equals(cmd)) { dumpState.setDump(DumpState.DUMP_KEYSETS); + } else if ("write".equals(cmd)) { + synchronized (mPackages) { + mSettings.writeLPr(); + pw.println("Settings written."); + return; + } } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index fd180bf..102b2d4 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -789,6 +789,7 @@ public class UserManagerService extends IUserManager.Stub { writeBoolean(serializer, restrictions, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA); writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE); writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADJUST_VOLUME); + writeBoolean(serializer, restrictions, UserManager.DISALLOW_TELEPHONY); serializer.endTag(null, TAG_RESTRICTIONS); } serializer.endTag(null, TAG_USER); @@ -941,6 +942,7 @@ public class UserManagerService extends IUserManager.Stub { UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA); readBoolean(parser, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE); readBoolean(parser, restrictions, UserManager.DISALLOW_ADJUST_VOLUME); + readBoolean(parser, restrictions, UserManager.DISALLOW_TELEPHONY); } } } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index c20e38c..e2d2ac6 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.IRemoteCallback; import android.os.SystemProperties; import android.util.Slog; +import android.view.View; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -34,7 +35,6 @@ import android.view.animation.AnimationUtils; import android.view.animation.ClipRectAnimation; import android.view.animation.Interpolator; import android.view.animation.ScaleAnimation; - import android.view.animation.TranslateAnimation; import com.android.internal.util.DumpUtils.Dump; import com.android.server.AttributeCache; @@ -500,7 +500,8 @@ public class AppTransition implements Dump { */ Animation createAlternateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, int appHeight, int orientation, int transit, - Rect containingFrame, Rect contentInsets) { + Rect containingFrame, Rect contentInsets, + boolean isFullScreen) { Animation a; final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; @@ -520,6 +521,9 @@ public class AppTransition implements Dump { scaledTopDecor = (int) (scale * contentInsets.top); int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); + if (isFullScreen) { + mTmpFromClipRect.top = contentInsets.top; + } mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); mTmpToClipRect.set(containingFrame); } else { @@ -527,7 +531,12 @@ public class AppTransition implements Dump { scale = thumbHeight / (appHeight - contentInsets.top); scaledTopDecor = (int) (scale * contentInsets.top); int unscaledThumbWidth = (int) (thumbWidth / scale); + int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); + if (isFullScreen) { + mTmpFromClipRect.top = contentInsets.top; + mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); + } mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth); mTmpToClipRect.set(containingFrame); } @@ -575,14 +584,22 @@ public class AppTransition implements Dump { int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); mTmpToClipRect.set(containingFrame); + if (isFullScreen) { + mTmpToClipRect.top = contentInsets.top; + } mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); } else { // In landscape, we scale the height and clip to the top/left square scale = thumbHeight / (appHeight - contentInsets.top); scaledTopDecor = (int) (scale * contentInsets.top); int unscaledThumbWidth = (int) (thumbWidth / scale); + int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); mTmpToClipRect.set(containingFrame); + if (isFullScreen) { + mTmpToClipRect.top = contentInsets.top; + mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); + } mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth); } @@ -679,7 +696,7 @@ public class AppTransition implements Dump { Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int appWidth, int appHeight, int orientation, - Rect containingFrame, Rect contentInsets) { + Rect containingFrame, Rect contentInsets, boolean isFullScreen) { Animation a; if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -702,7 +719,7 @@ public class AppTransition implements Dump { (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); a = createAlternateThumbnailEnterExitAnimationLocked( getThumbnailTransitionState(enter), appWidth, appHeight, orientation, - transit, containingFrame, contentInsets); + transit, containingFrame, contentInsets, isFullScreen); if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { String animName = mNextAppTransitionScaleUp ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c6fffbf..63a4f52 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -289,6 +289,11 @@ public class WindowManagerService extends IWindowManager.Stub private static final int MAX_SCREENSHOT_RETRIES = 3; + // The flag describing a full screen app window (where the app takes care of drawing under the + // SystemUI bars) + private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN = + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + final private KeyguardDisableHandler mKeyguardDisableHandler; final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -3193,8 +3198,11 @@ public class WindowManagerService extends IWindowManager.Stub } } + boolean isFullScreen = + ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) + == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN); Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height, - mCurConfiguration.orientation, containingFrame, contentInsets); + mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen); if (a != null) { if (DEBUG_ANIM) { RuntimeException e = null; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e2cd4e2..bc7742f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3384,6 +3384,93 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override + public boolean setApplicationBlocked(ComponentName who, String packageName, + boolean blocked) { + int callingUserId = UserHandle.getCallingUserId(); + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + IPackageManager pm = AppGlobals.getPackageManager(); + return pm.setApplicationBlockedSettingAsUser(packageName, blocked, callingUserId); + } catch (RemoteException re) { + // shouldn't happen + Slog.e(LOG_TAG, "Failed to setApplicationBlockedSetting", re); + } finally { + restoreCallingIdentity(id); + } + return false; + } + } + + @Override + public int setApplicationsBlocked(ComponentName who, Intent intent, boolean blocked) { + int callingUserId = UserHandle.getCallingUserId(); + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + IPackageManager pm = AppGlobals.getPackageManager(); + List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), + PackageManager.GET_DISABLED_COMPONENTS + | PackageManager.GET_UNINSTALLED_PACKAGES, + callingUserId); + + if (DBG) Slog.d(LOG_TAG, "Enabling activities: " + activitiesToEnable); + int numberOfAppsUnblocked = 0; + if (activitiesToEnable != null) { + for (ResolveInfo info : activitiesToEnable) { + if (info.activityInfo != null) { + numberOfAppsUnblocked++; + pm.setApplicationBlockedSettingAsUser(info.activityInfo.packageName, + blocked, callingUserId); + } + } + } + return numberOfAppsUnblocked; + } catch (RemoteException re) { + // shouldn't happen + Slog.e(LOG_TAG, "Failed to setApplicationsBlockedSettingsWithIntent", re); + } finally { + restoreCallingIdentity(id); + } + return 0; + } + } + + @Override + public boolean isApplicationBlocked(ComponentName who, String packageName) { + int callingUserId = UserHandle.getCallingUserId(); + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + IPackageManager pm = AppGlobals.getPackageManager(); + return pm.getApplicationBlockedSettingAsUser(packageName, callingUserId); + } catch (RemoteException re) { + // shouldn't happen + Slog.e(LOG_TAG, "Failed to getApplicationBlockedSettingAsUser", re); + } finally { + restoreCallingIdentity(id); + } + return false; + } + } + + @Override public void enableSystemApp(ComponentName who, String packageName) { synchronized (this) { if (who == null) { @@ -3595,4 +3682,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return false; } + + @Override + public void setGlobalSetting(ComponentName who, String setting, String value) { + final ContentResolver contentResolver = mContext.getContentResolver(); + + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + Settings.Global.putString(contentResolver, setting, value); + } finally { + restoreCallingIdentity(id); + } + } + } + + @Override + public void setSecureSetting(ComponentName who, String setting, String value) { + int callingUserId = UserHandle.getCallingUserId(); + final ContentResolver contentResolver = mContext.getContentResolver(); + + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + long id = Binder.clearCallingIdentity(); + try { + Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId); + } finally { + restoreCallingIdentity(id); + } + } + } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 9b3f7ac..55ae9c6 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -125,7 +125,7 @@ public final class SystemServer { private static final String WIFI_SERVICE_CLASS = "com.android.server.wifi.WifiService"; private static final String WIFI_PASSPOINT_SERVICE_CLASS = - "com.android.server.wifi.passpoint.WifiPasspointService"; + "com.android.server.wifi.passpoint.PasspointService"; private static final String WIFI_P2P_SERVICE_CLASS = "com.android.server.wifi.p2p.WifiP2pService"; private static final String HDMI_CEC_SERVICE_CLASS = @@ -639,15 +639,15 @@ public final class SystemServer { } try { - mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS); + mSystemServiceManager.startService(WIFI_SERVICE_CLASS); } catch (Throwable e) { - reportWtf("starting Wi-Fi PasspointService", e); + reportWtf("starting Wi-Fi Service", e); } try { - mSystemServiceManager.startService(WIFI_SERVICE_CLASS); + mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS); } catch (Throwable e) { - reportWtf("starting Wi-Fi Service", e); + reportWtf("starting Wi-Fi PasspointService", e); } try { diff --git a/tests/RenderThreadTest/Android.mk b/tests/RenderThreadTest/Android.mk index bdcba2e..e07e943 100644 --- a/tests/RenderThreadTest/Android.mk +++ b/tests/RenderThreadTest/Android.mk @@ -1,7 +1,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_TAGS := tests # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/RenderThreadTest/AndroidManifest.xml b/tests/RenderThreadTest/AndroidManifest.xml index c76cfce..a7f4f6e 100644 --- a/tests/RenderThreadTest/AndroidManifest.xml +++ b/tests/RenderThreadTest/AndroidManifest.xml @@ -4,10 +4,6 @@ android:versionCode="1" android:versionName="1.0" > - <uses-sdk - android:minSdkVersion="18" - android:targetSdkVersion="18" /> - <application android:allowBackup="true" android:icon="@drawable/ic_launcher" |
