diff options
author | Steve Kondik <steve@cyngn.com> | 2016-03-11 03:47:09 -0800 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2016-03-11 16:58:39 -0800 |
commit | 0e1dbed9194839a90755670d8fdf9046a75b85f7 (patch) | |
tree | 010372762ddc617295da2862f7d61813da9e3586 /core/java/android | |
parent | 564f10b8f05ddf4d9ea2c0e64f1b113fe6dad4b8 (diff) | |
parent | e342181a4a8d8177b3b87ffe141777565fe98f15 (diff) | |
download | frameworks_base-0e1dbed9194839a90755670d8fdf9046a75b85f7.zip frameworks_base-0e1dbed9194839a90755670d8fdf9046a75b85f7.tar.gz frameworks_base-0e1dbed9194839a90755670d8fdf9046a75b85f7.tar.bz2 |
Merge tag 'android-6.0.1_r22' of https://android.googlesource.com/platform/frameworks/base into cm-13.0
Android 6.0.1 release 22
Change-Id: I0d31899b234156a91accb61e0a7fb3d8d16d5062
Diffstat (limited to 'core/java/android')
32 files changed, 739 insertions, 297 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f08390f..782dc46 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4269,6 +4269,11 @@ public final class ActivityThread { configDiff = mConfiguration.updateFrom(config); config = applyCompatConfiguration(mCurDefaultDisplayDpi); + + final Theme systemTheme = getSystemContext().getTheme(); + if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { + systemTheme.rebase(); + } } ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 9c0d931..c075ed6 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -24,8 +24,6 @@ import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.graphics.SurfaceTexture; -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.OperationCanceledException; @@ -45,6 +43,17 @@ import android.view.WindowManager; import dalvik.system.CloseGuard; import java.lang.ref.WeakReference; +import java.util.ArrayDeque; +import java.util.concurrent.Executor; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import com.android.internal.annotations.GuardedBy; + /** @hide */ public class ActivityView extends ViewGroup { @@ -53,9 +62,64 @@ public class ActivityView extends ViewGroup { private static final int MSG_SET_SURFACE = 1; - DisplayMetrics mMetrics = new DisplayMetrics(); + private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); + private static final int MINIMUM_POOL_SIZE = 1; + private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; + private static final int KEEP_ALIVE = 1; + + private static final ThreadFactory sThreadFactory = new ThreadFactory() { + private final AtomicInteger mCount = new AtomicInteger(1); + + public Thread newThread(Runnable r) { + return new Thread(r, "ActivityView #" + mCount.getAndIncrement()); + } + }; + + private static final BlockingQueue<Runnable> sPoolWorkQueue = + new LinkedBlockingQueue<Runnable>(128); + + /** + * An {@link Executor} that can be used to execute tasks in parallel. + */ + private static final Executor sExecutor = new ThreadPoolExecutor(MINIMUM_POOL_SIZE, + MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); + + + private static class SerialExecutor implements Executor { + private final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); + private Runnable mActive; + + public synchronized void execute(final Runnable r) { + mTasks.offer(new Runnable() { + public void run() { + try { + r.run(); + } finally { + scheduleNext(); + } + } + }); + if (mActive == null) { + scheduleNext(); + } + } + + protected synchronized void scheduleNext() { + if ((mActive = mTasks.poll()) != null) { + sExecutor.execute(mActive); + } + } + } + + private final SerialExecutor mExecutor = new SerialExecutor(); + + private final int mDensityDpi; private final TextureView mTextureView; + + @GuardedBy("mActivityContainerLock") private ActivityContainerWrapper mActivityContainer; + private Object mActivityContainerLock = new Object(); + private Activity mActivity; private int mWidth; private int mHeight; @@ -63,8 +127,6 @@ public class ActivityView extends ViewGroup { private int mLastVisibility; private ActivityViewCallback mActivityViewCallback; - private HandlerThread mThread = new HandlerThread("ActivityViewThread"); - private Handler mHandler; public ActivityView(Context context) { this(context, null); @@ -97,28 +159,14 @@ public class ActivityView extends ViewGroup { + e); } - mThread.start(); - mHandler = new Handler(mThread.getLooper()) { - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - if (msg.what == MSG_SET_SURFACE) { - try { - mActivityContainer.setSurface((Surface) msg.obj, msg.arg1, msg.arg2, - mMetrics.densityDpi); - } catch (RemoteException e) { - throw new RuntimeException( - "ActivityView: Unable to set surface of ActivityContainer. " + e); - } - } - } - }; mTextureView = new TextureView(context); mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); addView(mTextureView); WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); - wm.getDefaultDisplay().getMetrics(mMetrics); + DisplayMetrics metrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics(metrics); + mDensityDpi = metrics.densityDpi; mLastVisibility = getVisibility(); @@ -131,15 +179,13 @@ public class ActivityView extends ViewGroup { } @Override - protected void onVisibilityChanged(View changedView, int visibility) { + protected void onVisibilityChanged(View changedView, final int visibility) { super.onVisibilityChanged(changedView, visibility); if (mSurface != null && (visibility == View.GONE || mLastVisibility == View.GONE)) { - Message msg = Message.obtain(mHandler, MSG_SET_SURFACE); - msg.obj = (visibility == View.GONE) ? null : mSurface; - msg.arg1 = mWidth; - msg.arg2 = mHeight; - mHandler.sendMessage(msg); + if (DEBUG) Log.v(TAG, "visibility changed; enqueing runnable"); + final Surface surface = (visibility == View.GONE) ? null : mSurface; + setSurfaceAsync(surface, mWidth, mHeight, mDensityDpi, false); } mLastVisibility = visibility; } @@ -230,8 +276,10 @@ public class ActivityView extends ViewGroup { Log.e(TAG, "Duplicate call to release"); return; } - mActivityContainer.release(); - mActivityContainer = null; + synchronized (mActivityContainerLock) { + mActivityContainer.release(); + mActivityContainer = null; + } if (mSurface != null) { mSurface.release(); @@ -241,21 +289,37 @@ public class ActivityView extends ViewGroup { mTextureView.setSurfaceTextureListener(null); } - private void attachToSurfaceWhenReady() { - final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); - if (surfaceTexture == null || mSurface != null) { - // Either not ready to attach, or already attached. - return; - } - - mSurface = new Surface(surfaceTexture); - try { - mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi); - } catch (RemoteException e) { - mSurface.release(); - mSurface = null; - throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e); - } + private void setSurfaceAsync(final Surface surface, final int width, final int height, + final int densityDpi, final boolean callback) { + mExecutor.execute(new Runnable() { + public void run() { + try { + synchronized (mActivityContainerLock) { + if (mActivityContainer != null) { + mActivityContainer.setSurface(surface, width, height, densityDpi); + } + } + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to set surface of ActivityContainer. ", + e); + } + if (callback) { + post(new Runnable() { + @Override + public void run() { + if (mActivityViewCallback != null) { + if (surface != null) { + mActivityViewCallback.onSurfaceAvailable(ActivityView.this); + } else { + mActivityViewCallback.onSurfaceDestroyed(ActivityView.this); + } + } + } + }); + } + } + }); } /** @@ -306,10 +370,8 @@ public class ActivityView extends ViewGroup { + height); mWidth = width; mHeight = height; - attachToSurfaceWhenReady(); - if (mActivityViewCallback != null) { - mActivityViewCallback.onSurfaceAvailable(ActivityView.this); - } + mSurface = new Surface(surfaceTexture); + setSurfaceAsync(mSurface, mWidth, mHeight, mDensityDpi, true); } @Override @@ -329,15 +391,7 @@ public class ActivityView extends ViewGroup { if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed"); mSurface.release(); mSurface = null; - try { - mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi); - } catch (RemoteException e) { - throw new RuntimeException( - "ActivityView: Unable to set surface of ActivityContainer. " + e); - } - if (mActivityViewCallback != null) { - mActivityViewCallback.onSurfaceDestroyed(ActivityView.this); - } + setSurfaceAsync(null, mWidth, mHeight, mDensityDpi, true); return true; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index cd07c9c..d8e01cd 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -45,6 +45,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.util.MathUtils; +import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -62,6 +63,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Set; /** * A class that represents how a persistent notification is to be presented to @@ -960,6 +963,9 @@ public class Notification implements Parcelable private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs) { this.mIcon = icon; + if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { + this.icon = icon.getResId(); + } this.title = title; this.actionIntent = intent; this.mExtras = extras != null ? extras : new Bundle(); @@ -1607,13 +1613,23 @@ public class Notification implements Parcelable bigContentView = null; headsUpContentView = null; mLargeIcon = null; - if (extras != null) { - extras.remove(Notification.EXTRA_LARGE_ICON); - extras.remove(Notification.EXTRA_LARGE_ICON_BIG); - extras.remove(Notification.EXTRA_PICTURE); - extras.remove(Notification.EXTRA_BIG_TEXT); + if (extras != null && !extras.isEmpty()) { // Prevent light notifications from being rebuilt. extras.remove(Builder.EXTRA_NEEDS_REBUILD); + final Set<String> keyset = extras.keySet(); + final int N = keyset.size(); + final String[] keys = keyset.toArray(new String[N]); + for (int i=0; i<N; i++) { + final String key = keys[i]; + final Object obj = extras.get(key); + if (obj != null && + ( obj instanceof Parcelable + || obj instanceof Parcelable[] + || obj instanceof SparseArray + || obj instanceof ArrayList)) { + extras.remove(key); + } + } } } @@ -4619,7 +4635,7 @@ public class Notification implements Parcelable * Size value for use with {@link #setCustomSizePreset} to show this notification with * default sizing. * <p>For custom display notifications created using {@link #setDisplayIntent}, - * the default is {@link #SIZE_LARGE}. All other notifications size automatically based + * the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based * on their content. */ public static final int SIZE_DEFAULT = 0; diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java index 0fce4e2..a88aa31 100644 --- a/core/java/android/app/usage/UsageStats.java +++ b/core/java/android/app/usage/UsageStats.java @@ -165,14 +165,18 @@ public final class UsageStats implements Parcelable { mPackageName + "' with UsageStats for package '" + right.mPackageName + "'."); } - if (right.mEndTimeStamp > mEndTimeStamp) { + if (right.mBeginTimeStamp > mBeginTimeStamp) { + // The incoming UsageStat begins after this one, so use its last time used fields + // as the source of truth. + // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with + // regards to their mEndTimeStamp. mLastEvent = right.mLastEvent; - mEndTimeStamp = right.mEndTimeStamp; mLastTimeUsed = right.mLastTimeUsed; mBeginIdleTime = right.mBeginIdleTime; mLastTimeSystemUsed = right.mLastTimeSystemUsed; } mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp); + mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp); mTotalTimeInForeground += right.mTotalTimeInForeground; mLaunchCount += right.mLaunchCount; } diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index e742b2b..b4006de 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -25,6 +25,7 @@ import android.content.Context; import android.os.Parcel; import android.os.Parcelable; import android.os.ParcelUuid; +import android.os.Process; import android.os.RemoteException; import android.util.Log; @@ -823,6 +824,9 @@ public final class BluetoothDevice implements Parcelable { return false; } try { + Log.i(TAG, "createBond() for device " + getAddress() + + " called by pid: " + Process.myPid() + + " tid: " + Process.myTid()); return sService.createBond(this, TRANSPORT_AUTO); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; @@ -854,6 +858,9 @@ public final class BluetoothDevice implements Parcelable { throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport"); } try { + Log.i(TAG, "createBond() for device " + getAddress() + + " called by pid: " + Process.myPid() + + " tid: " + Process.myTid()); return sService.createBond(this, transport); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; @@ -922,6 +929,9 @@ public final class BluetoothDevice implements Parcelable { return false; } try { + Log.i(TAG, "cancelBondProcess() for device " + getAddress() + + " called by pid: " + Process.myPid() + + " tid: " + Process.myTid()); return sService.cancelBondProcess(this); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; @@ -943,6 +953,9 @@ public final class BluetoothDevice implements Parcelable { return false; } try { + Log.i(TAG, "removeBond() for device " + getAddress() + + " called by pid: " + Process.myPid() + + " tid: " + Process.myTid()); return sService.removeBond(this); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index f513652..da81032 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -710,6 +710,48 @@ public final class BluetoothHeadset implements BluetoothProfile { } /** + * Sets whether audio routing is allowed. When set to {@code false}, the AG will not route any + * audio to the HF unless explicitly told to. + * This method should be used in cases where the SCO channel is shared between multiple profiles + * and must be delegated by a source knowledgeable + * Note: This is an internal function and shouldn't be exposed + * + * @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise. + * + * @hide + */ + public void setAudioRouteAllowed(boolean allowed) { + if (VDBG) log("setAudioRouteAllowed"); + if (mService != null && isEnabled()) { + try { + mService.setAudioRouteAllowed(allowed); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + } + + /** + * Returns whether audio routing is allowed. see {@link #setAudioRouteAllowed(boolean)}. + * Note: This is an internal function and shouldn't be exposed + * + * @hide + */ + public boolean getAudioRouteAllowed() { + if (VDBG) log("getAudioRouteAllowed"); + if (mService != null && isEnabled()) { + try { + return mService.getAudioRouteAllowed(); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** * Check if Bluetooth SCO audio is connected. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 10d851f..484a856 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -1076,6 +1076,41 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { } /** + * Sets whether audio routing is allowed. + * + * Note: This is an internal function and shouldn't be exposed + */ + public void setAudioRouteAllowed(boolean allowed) { + if (VDBG) log("setAudioRouteAllowed"); + if (mService != null && isEnabled()) { + try { + mService.setAudioRouteAllowed(allowed); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + } + + /** + * Returns whether audio routing is allowed. + * + * Note: This is an internal function and shouldn't be exposed + */ + public boolean getAudioRouteAllowed() { + if (VDBG) log("getAudioRouteAllowed"); + if (mService != null && isEnabled()) { + try { + return mService.getAudioRouteAllowed(); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** * Initiates a connection of audio channel. * * It setup SCO channel with remote connected Handsfree AG device. diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java index 7b5a045..002f63f 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java @@ -19,6 +19,8 @@ package android.bluetooth; import android.os.Parcel; import android.os.Parcelable; +import java.util.UUID; + /** * This class represents a single call, its state and properties. * It implements {@link Parcelable} for inter-process message passing. @@ -67,14 +69,21 @@ public final class BluetoothHeadsetClientCall implements Parcelable { private String mNumber; private boolean mMultiParty; private final boolean mOutgoing; + private final UUID mUUID; /** * Creates BluetoothHeadsetClientCall instance. */ public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number, boolean multiParty, boolean outgoing) { + this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing); + } + + public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state, + String number, boolean multiParty, boolean outgoing) { mDevice = device; mId = id; + mUUID = uuid; mState = state; mNumber = number != null ? number : ""; mMultiParty = multiParty; @@ -134,6 +143,16 @@ public final class BluetoothHeadsetClientCall implements Parcelable { } /** + * Gets call's UUID. + * + * @return call uuid + * @hide + */ + public UUID getUUID() { + return mUUID; + } + + /** * Gets call's current state. * * @return state of this particular phone call. @@ -172,10 +191,16 @@ public final class BluetoothHeadsetClientCall implements Parcelable { } public String toString() { + return toString(false); + } + + public String toString(boolean loggable) { StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: "); - builder.append(mDevice); + builder.append(loggable ? mDevice.hashCode() : mDevice); builder.append(", mId: "); builder.append(mId); + builder.append(", mUUID: "); + builder.append(mUUID); builder.append(", mState: "); switch (mState) { case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break; @@ -189,7 +214,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable { default: builder.append(mState); break; } builder.append(", mNumber: "); - builder.append(mNumber); + builder.append(loggable ? mNumber.hashCode() : mNumber); builder.append(", mMultiParty: "); builder.append(mMultiParty); builder.append(", mOutgoing: "); @@ -206,8 +231,8 @@ public final class BluetoothHeadsetClientCall implements Parcelable { @Override public BluetoothHeadsetClientCall createFromParcel(Parcel in) { return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null), - in.readInt(), in.readInt(), in.readString(), - in.readInt() == 1, in.readInt() == 1); + in.readInt(), UUID.fromString(in.readString()), in.readInt(), + in.readString(), in.readInt() == 1, in.readInt() == 1); } @Override @@ -220,6 +245,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeParcelable(mDevice, 0); out.writeInt(mId); + out.writeString(mUUID.toString()); out.writeInt(mState); out.writeString(mNumber); out.writeInt(mMultiParty ? 1 : 0); diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl index 0e23fad..0bb4088 100755 --- a/core/java/android/bluetooth/IBluetoothHeadset.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl @@ -50,6 +50,8 @@ interface IBluetoothHeadset { boolean isAudioOn(); boolean connectAudio(); boolean disconnectAudio(); + void setAudioRouteAllowed(boolean allowed); + boolean getAudioRouteAllowed(); boolean startScoUsingVirtualVoiceCall(in BluetoothDevice device); boolean stopScoUsingVirtualVoiceCall(in BluetoothDevice device); void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type); diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl index e518b7d..79ae4e4 100644 --- a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl @@ -62,6 +62,8 @@ interface IBluetoothHeadsetClient { int getAudioState(in BluetoothDevice device); boolean connectAudio(); boolean disconnectAudio(); + void setAudioRouteAllowed(boolean allowed); + boolean getAudioRouteAllowed(); Bundle getCurrentAgFeatures(in BluetoothDevice device); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index d063454..c06f98a 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1605,6 +1605,23 @@ public class Intent implements Parcelable, Cloneable { = "android.intent.action.GET_PERMISSIONS_COUNT"; /** + * Broadcast action that requests list of all apps that have runtime permissions. It will + * respond to the request by sending a broadcast with action defined by + * {@link #EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT}. The response will contain + * {@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT}, as well as + * {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}, with contents described below or + * a null upon failure. + * + * <p>{@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT} will contain a list of package names of + * apps that have runtime permissions. {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT} + * will contain the list of app labels corresponding ot the apps in the first list. + * + * @hide + */ + public static final String ACTION_GET_PERMISSIONS_PACKAGES + = "android.intent.action.GET_PERMISSIONS_PACKAGES"; + + /** * Extra included in response to {@link #ACTION_GET_PERMISSIONS_COUNT}. * @hide */ @@ -1619,6 +1636,28 @@ public class Intent implements Parcelable, Cloneable { = "android.intent.extra.GET_PERMISSIONS_GROUP_LIST_RESULT"; /** + * String list of apps that have one or more runtime permissions. + * @hide + */ + public static final String EXTRA_GET_PERMISSIONS_APP_LIST_RESULT + = "android.intent.extra.GET_PERMISSIONS_APP_LIST_RESULT"; + + /** + * String list of app labels for apps that have one or more runtime permissions. + * @hide + */ + public static final String EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT + = "android.intent.extra.GET_PERMISSIONS_APP_LABEL_LIST_RESULT"; + + /** + * Boolean list describing if the app is a system app for apps that have one or more runtime + * permissions. + * @hide + */ + public static final String EXTRA_GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT + = "android.intent.extra.GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT"; + + /** * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts. * @hide */ @@ -1626,6 +1665,13 @@ public class Intent implements Parcelable, Cloneable { = "android.intent.extra.GET_PERMISSIONS_RESONSE_INTENT"; /** + * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_PACKAGES} broadcasts. + * @hide + */ + public static final String EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT + = "android.intent.extra.GET_PERMISSIONS_PACKAGES_RESONSE_INTENT"; + + /** * Activity action: Launch UI to manage which apps have a given permission. * <p> * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access @@ -3066,6 +3112,39 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_DOZE_PULSE_STARTING = "android.intent.action.DOZE_PULSE_STARTING"; + /** + * Broadcast action: reports when a new thermal event has been reached. When the device + * is reaching its maximum temperatue, the thermal level reported + * {@hide} + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_THERMAL_EVENT = "android.intent.action.THERMAL_EVENT"; + + /** {@hide} */ + public static final String EXTRA_THERMAL_STATE = "android.intent.extra.THERMAL_STATE"; + + /** + * Thermal state when the device is normal. This state is sent in the + * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}. + * {@hide} + */ + public static final int EXTRA_THERMAL_STATE_NORMAL = 0; + + /** + * Thermal state where the device is approaching its maximum threshold. This state is sent in + * the {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}. + * {@hide} + */ + public static final int EXTRA_THERMAL_STATE_WARNING = 1; + + /** + * Thermal state where the device has reached its maximum threshold. This state is sent in the + * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}. + * {@hide} + */ + public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2; + + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). @@ -3168,6 +3247,13 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_HOME = "android.intent.category.HOME"; /** + * This is the home activity that is displayed when the device is finished setting up and ready + * for use. + * @hide + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_HOME_MAIN = "android.intent.category.HOME_MAIN"; + /** * This is the setup wizard activity, that is the first activity that is displayed * when the user sets up the device for the first time. * @hide diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 85ecc0a..6a404e2 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1554,10 +1554,12 @@ public class Resources { * if not already defined in the theme. */ public void applyStyle(int resId, boolean force) { - AssetManager.applyThemeStyle(mTheme, resId, force); + synchronized (mKey) { + AssetManager.applyThemeStyle(mTheme, resId, force); - mThemeResId = resId; - mKey.append(resId, force); + mThemeResId = resId; + mKey.append(resId, force); + } } /** @@ -1570,10 +1572,14 @@ public class Resources { * @param other The existing Theme to copy from. */ public void setTo(Theme other) { - AssetManager.copyTheme(mTheme, other.mTheme); + synchronized (mKey) { + synchronized (other.mKey) { + AssetManager.copyTheme(mTheme, other.mTheme); - mThemeResId = other.mThemeResId; - mKey.setTo(other.getKey()); + mThemeResId = other.mThemeResId; + mKey.setTo(other.getKey()); + } + } } /** @@ -1596,11 +1602,13 @@ public class Resources { * @see #obtainStyledAttributes(AttributeSet, int[], int, int) */ public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) { - final int len = attrs.length; - final TypedArray array = TypedArray.obtain(Resources.this, len); - array.mTheme = this; - AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices); - return array; + synchronized (mKey) { + final int len = attrs.length; + final TypedArray array = TypedArray.obtain(Resources.this, len); + array.mTheme = this; + AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices); + return array; + } } /** @@ -1610,7 +1618,7 @@ public class Resources { * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done * with the array. * - * @param resid The desired style resource. + * @param resId The desired style resource. * @param attrs The desired attributes in the style. * * @throws NotFoundException Throws NotFoundException if the given ID does not exist. @@ -1623,39 +1631,15 @@ public class Resources { * @see #obtainStyledAttributes(int[]) * @see #obtainStyledAttributes(AttributeSet, int[], int, int) */ - public TypedArray obtainStyledAttributes(@StyleRes int resid, @StyleableRes int[] attrs) + public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs) throws NotFoundException { - final int len = attrs.length; - final TypedArray array = TypedArray.obtain(Resources.this, len); - array.mTheme = this; - if (false) { - int[] data = array.mData; - - System.out.println("**********************************************************"); - System.out.println("**********************************************************"); - System.out.println("**********************************************************"); - System.out.println("Attributes:"); - String s = " Attrs:"; - int i; - for (i=0; i<attrs.length; i++) { - s = s + " 0x" + Integer.toHexString(attrs[i]); - } - System.out.println(s); - s = " Found:"; - TypedValue value = new TypedValue(); - for (i=0; i<attrs.length; i++) { - int d = i*AssetManager.STYLE_NUM_ENTRIES; - value.type = data[d+AssetManager.STYLE_TYPE]; - value.data = data[d+AssetManager.STYLE_DATA]; - value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE]; - value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID]; - s = s + " 0x" + Integer.toHexString(attrs[i]) - + "=" + value; - } - System.out.println(s); + synchronized (mKey) { + final int len = attrs.length; + final TypedArray array = TypedArray.obtain(Resources.this, len); + array.mTheme = this; + AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices); + return array; } - AssetManager.applyStyle(mTheme, 0, resid, 0, attrs, array.mData, array.mIndices); - return array; } /** @@ -1708,50 +1692,23 @@ public class Resources { */ public TypedArray obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { - final int len = attrs.length; - final TypedArray array = TypedArray.obtain(Resources.this, len); - - // XXX note that for now we only work with compiled XML files. - // To support generic XML files we will need to manually parse - // out the attributes from the XML file (applying type information - // contained in the resources and such). - final XmlBlock.Parser parser = (XmlBlock.Parser)set; - AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, - parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices); + synchronized (mKey) { + final int len = attrs.length; + final TypedArray array = TypedArray.obtain(Resources.this, len); - array.mTheme = this; - array.mXml = parser; + // XXX note that for now we only work with compiled XML files. + // To support generic XML files we will need to manually parse + // out the attributes from the XML file (applying type information + // contained in the resources and such). + final XmlBlock.Parser parser = (XmlBlock.Parser) set; + AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, + parser != null ? parser.mParseState : 0, + attrs, array.mData, array.mIndices); + array.mTheme = this; + array.mXml = parser; - if (false) { - int[] data = array.mData; - - System.out.println("Attributes:"); - String s = " Attrs:"; - int i; - for (i=0; i<set.getAttributeCount(); i++) { - s = s + " " + set.getAttributeName(i); - int id = set.getAttributeNameResource(i); - if (id != 0) { - s = s + "(0x" + Integer.toHexString(id) + ")"; - } - s = s + "=" + set.getAttributeValue(i); - } - System.out.println(s); - s = " Found:"; - TypedValue value = new TypedValue(); - for (i=0; i<attrs.length; i++) { - int d = i*AssetManager.STYLE_NUM_ENTRIES; - value.type = data[d+AssetManager.STYLE_TYPE]; - value.data = data[d+AssetManager.STYLE_DATA]; - value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE]; - value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID]; - s = s + " 0x" + Integer.toHexString(attrs[i]) - + "=" + value; - } - System.out.println(s); + return array; } - - return array; } /** @@ -1770,18 +1727,20 @@ public class Resources { */ @NonNull public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) { - final int len = attrs.length; - if (values == null || len != values.length) { - throw new IllegalArgumentException( - "Base attribute values must the same length as attrs"); - } + synchronized (mKey) { + final int len = attrs.length; + if (values == null || len != values.length) { + throw new IllegalArgumentException( + "Base attribute values must the same length as attrs"); + } - final TypedArray array = TypedArray.obtain(Resources.this, len); - AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices); - array.mTheme = this; - array.mXml = null; + final TypedArray array = TypedArray.obtain(Resources.this, len); + AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices); + array.mTheme = this; + array.mXml = null; - return array; + return array; + } } /** @@ -1802,14 +1761,9 @@ public class Resources { * <var>outValue</var> is valid, else false. */ public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) { - boolean got = mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs); - if (false) { - System.out.println( - "resolveAttribute #" + Integer.toHexString(resid) - + " got=" + got + ", type=0x" + Integer.toHexString(outValue.type) - + ", data=0x" + Integer.toHexString(outValue.data)); + synchronized (mKey) { + return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs); } - return got; } /** @@ -1855,8 +1809,11 @@ public class Resources { * @see ActivityInfo */ public int getChangingConfigurations() { - final int nativeChangingConfig = AssetManager.getThemeChangingConfigurations(mTheme); - return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig); + synchronized (mKey) { + final int nativeChangingConfig = + AssetManager.getThemeChangingConfigurations(mTheme); + return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig); + } } /** @@ -1867,7 +1824,9 @@ public class Resources { * @param prefix Text to prefix each line printed. */ public void dump(int priority, String tag, String prefix) { - AssetManager.dumpTheme(mTheme, priority, tag, prefix); + synchronized (mKey) { + AssetManager.dumpTheme(mTheme, priority, tag, prefix); + } } @Override @@ -1917,19 +1876,21 @@ public class Resources { */ @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true) public String[] getTheme() { - final int N = mKey.mCount; - final String[] themes = new String[N * 2]; - for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) { - final int resId = mKey.mResId[j]; - final boolean forced = mKey.mForce[j]; - try { - themes[i] = getResourceName(resId); - } catch (NotFoundException e) { - themes[i] = Integer.toHexString(i); + synchronized (mKey) { + final int N = mKey.mCount; + final String[] themes = new String[N * 2]; + for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) { + final int resId = mKey.mResId[j]; + final boolean forced = mKey.mForce[j]; + try { + themes[i] = getResourceName(resId); + } catch (NotFoundException e) { + themes[i] = Integer.toHexString(i); + } + themes[i + 1] = forced ? "forced" : "not forced"; } - themes[i + 1] = forced ? "forced" : "not forced"; + return themes; } - return themes; } /** @hide */ @@ -1950,13 +1911,15 @@ public class Resources { * @hide */ public void rebase() { - AssetManager.clearTheme(mTheme); - - // Reapply the same styles in the same order. - for (int i = 0; i < mKey.mCount; i++) { - final int resId = mKey.mResId[i]; - final boolean force = mKey.mForce[i]; - AssetManager.applyThemeStyle(mTheme, resId, force); + synchronized (mKey) { + AssetManager.clearTheme(mTheme); + + // Reapply the same styles in the same order. + for (int i = 0; i < mKey.mCount; i++) { + final int resId = mKey.mResId[i]; + final boolean force = mKey.mForce[i]; + AssetManager.applyThemeStyle(mTheme, resId, force); + } } } } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 940f9e5..dd15d38 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -3485,8 +3485,8 @@ public class Camera { } /** - * Sets GPS processing method. It will store up to 32 characters - * in JPEG EXIF header. + * Sets GPS processing method. The method will be stored in a UTF-8 string up to 31 bytes + * long, in the JPEG EXIF header. * * @param processing_method The processing method to get this location. */ diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index a2ef078..7464211 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -398,17 +398,24 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * this camera device.</p> * <p>For devices at the LEGACY level or above:</p> * <ul> - * <li>This list will always include (30, 30).</li> - * <li>Also, for constant-framerate recording, for each normal + * <li> + * <p>For constant-framerate recording, for each normal + * {@link android.media.CamcorderProfile CamcorderProfile}, that is, a * {@link android.media.CamcorderProfile CamcorderProfile} that has * {@link android.media.CamcorderProfile#quality quality} in * the range [{@link android.media.CamcorderProfile#QUALITY_LOW QUALITY_LOW}, * {@link android.media.CamcorderProfile#QUALITY_2160P QUALITY_2160P}], if the profile is * supported by the device and has * {@link android.media.CamcorderProfile#videoFrameRate videoFrameRate} <code>x</code>, this list will - * always include (<code>x</code>,<code>x</code>).</li> - * <li>For preview streaming use case, this list will always include (<code>min</code>, <code>max</code>) where - * <code>min</code> <= 15 and <code>max</code> >= 30.</li> + * always include (<code>x</code>,<code>x</code>).</p> + * </li> + * <li> + * <p>Also, a camera device must either not support any + * {@link android.media.CamcorderProfile CamcorderProfile}, + * or support at least one + * normal {@link android.media.CamcorderProfile CamcorderProfile} that has + * {@link android.media.CamcorderProfile#videoFrameRate videoFrameRate} <code>x</code> >= 24.</p> + * </li> * </ul> * <p>For devices at the LIMITED level or above:</p> * <ul> diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 35a1d96..f61892e 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -472,13 +472,13 @@ public abstract class CameraMetadata<TKey> { * <li>The maximum available resolution for RAW_SENSOR streams * will match either the value in * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li> + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.</li> * <li>All DNG-related optional metadata entries are provided * by the camera device.</li> * </ul> * - * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES */ public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 3f566eb..67835a0 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -556,6 +556,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * Set a capture request field to a value. The field definitions can be * found in {@link CaptureRequest}. * + * <p>Setting a field to {@code null} will remove that field from the capture request. + * Unless the field is optional, removing it will likely produce an error from the camera + * device when the request is submitted.</p> + * * @param key The metadata field to write. * @param value The value to set the field to, which must be of a matching * type to the key. diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 7f5f377..9e639e8 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -48,6 +48,9 @@ interface INetworkPolicyManager { /** Snooze limit on policy matching given template. */ void snoozeLimit(in NetworkTemplate template); + /** Snooze warning on policy matching given template. */ + void snoozeWarning(in NetworkTemplate template); + /** Control if background data is restricted system-wide. */ void setRestrictBackground(boolean restrictBackground); boolean getRestrictBackground(); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index a83e722..eab22b8 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.GET_SIGNATURES; import static android.net.NetworkPolicy.CYCLE_NONE; import static android.text.format.Time.MONTH_DAY; +import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -81,6 +82,54 @@ public class NetworkPolicyManager { */ public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE"; + /** + * Broadcast intent action for informing a custom component about a network policy + * notification. + * @hide + */ + @SystemApi + public static final String ACTION_SHOW_NETWORK_POLICY_NOTIFICATION = + "android.net.action.SHOW_NETWORK_POLICY_NOTIFICATION"; + + /** + * The sequence number associated with the notification - a higher number + * indicates previous notifications may be disregarded. + * @hide + */ + @SystemApi + public static final String EXTRA_NOTIFICATION_SEQUENCE_NUMBER = + "android.net.extra.NOTIFICATION_SEQUENCE_NUMBER"; + + /** + * The type of notification that should be presented to the user. + * @hide + */ + @SystemApi + public static final String EXTRA_NOTIFICATION_TYPE = "android.net.extra.NOTIFICATION_TYPE"; + + @SystemApi + public static final int NOTIFICATION_TYPE_NONE = 0; + @SystemApi + public static final int NOTIFICATION_TYPE_USAGE_WARNING = 1; + @SystemApi + public static final int NOTIFICATION_TYPE_USAGE_REACHED_LIMIT = 2; + @SystemApi + public static final int NOTIFICATION_TYPE_USAGE_EXCEEDED_LIMIT = 3; + + /** + * The number of bytes used on the network in the notification. + * @hide + */ + @SystemApi + public static final String EXTRA_BYTES_USED = "android.net.extra.BYTES_USED"; + + /** + * The network policy for the network in the notification. + * @hide + */ + @SystemApi + public static final String EXTRA_NETWORK_POLICY = "android.net.extra.NETWORK_POLICY"; + private final Context mContext; private INetworkPolicyManager mService; diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java index 29daf35..5880e5d 100644 --- a/core/java/android/net/NetworkScorerAppManager.java +++ b/core/java/android/net/NetworkScorerAppManager.java @@ -33,6 +33,7 @@ import android.util.Log; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -90,8 +91,13 @@ public final class NetworkScorerAppManager { * @return the list of scorers, or the empty list if there are no valid scorers. */ public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) { - List<NetworkScorerAppData> scorers = new ArrayList<>(); + // Network scorer apps can only run as the primary user so exit early if we're not the + // primary user. + if (UserHandle.getCallingUserId() != 0 /*USER_SYSTEM*/) { + return Collections.emptyList(); + } + List<NetworkScorerAppData> scorers = new ArrayList<>(); PackageManager pm = context.getPackageManager(); // Only apps installed under the primary user of the device can be scorers. List<ResolveInfo> receivers = @@ -104,8 +110,9 @@ public final class NetworkScorerAppManager { continue; } if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) { - // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means - // anyone could trigger network scoring and flood the framework with score requests. + // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which + // means anyone could trigger network scoring and flood the framework with score + // requests. continue; } if (pm.checkPermission(permission.SCORE_NETWORKS, receiverInfo.packageName) != @@ -127,8 +134,8 @@ public final class NetworkScorerAppManager { } } - // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app - // label if none is present. + // NOTE: loadLabel will attempt to load the receiver's label and fall back to the + // app label if none is present. scorers.add(new NetworkScorerAppData(receiverInfo.packageName, receiverInfo.applicationInfo.uid, receiverInfo.loadLabel(pm), configurationActivityClassName)); diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java index d619c0a..c7d4c65 100644 --- a/core/java/android/nfc/NfcActivityManager.java +++ b/core/java/android/nfc/NfcActivityManager.java @@ -371,40 +371,44 @@ public final class NfcActivityManager extends IAppCallback.Stub flags = state.flags; activity = state.activity; } - - // Make callbacks without lock - if (ndefCallback != null) { - message = ndefCallback.createNdefMessage(event); - } - if (urisCallback != null) { - uris = urisCallback.createBeamUris(event); - if (uris != null) { - ArrayList<Uri> validUris = new ArrayList<Uri>(); - for (Uri uri : uris) { - if (uri == null) { - Log.e(TAG, "Uri not allowed to be null."); - continue; - } - String scheme = uri.getScheme(); - if (scheme == null || (!scheme.equalsIgnoreCase("file") && - !scheme.equalsIgnoreCase("content"))) { - Log.e(TAG, "Uri needs to have " + - "either scheme file or scheme content"); - continue; + final long ident = Binder.clearCallingIdentity(); + try { + // Make callbacks without lock + if (ndefCallback != null) { + message = ndefCallback.createNdefMessage(event); + } + if (urisCallback != null) { + uris = urisCallback.createBeamUris(event); + if (uris != null) { + ArrayList<Uri> validUris = new ArrayList<Uri>(); + for (Uri uri : uris) { + if (uri == null) { + Log.e(TAG, "Uri not allowed to be null."); + continue; + } + String scheme = uri.getScheme(); + if (scheme == null || (!scheme.equalsIgnoreCase("file") && + !scheme.equalsIgnoreCase("content"))) { + Log.e(TAG, "Uri needs to have " + + "either scheme file or scheme content"); + continue; + } + uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId()); + validUris.add(uri); } - uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId()); - validUris.add(uri); - } - uris = validUris.toArray(new Uri[validUris.size()]); + uris = validUris.toArray(new Uri[validUris.size()]); + } } - } - if (uris != null && uris.length > 0) { - for (Uri uri : uris) { - // Grant the NFC process permission to read these URIs - activity.grantUriPermission("com.android.nfc", uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION); + if (uris != null && uris.length > 0) { + for (Uri uri : uris) { + // Grant the NFC process permission to read these URIs + activity.grantUriPermission("com.android.nfc", uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION); + } } + } finally { + Binder.restoreCallingIdentity(ident); } return new BeamShareData(message, uris, new UserHandle(UserHandle.myUserId()), flags); } diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index 38037a6..39c12f0 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -117,6 +117,12 @@ public abstract class PowerManagerInternal { public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis); /** + * Used by the window manager to tell the power manager that the user is no longer actively + * using the device. + */ + public abstract void setUserInactiveOverrideFromWindowManager(); + + /** * Used by device administration to set the maximum screen off timeout. * * This method must only be called by the device administration policy manager. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6663727..f6642d8 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6438,6 +6438,13 @@ public final class Settings { public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios"; /** + * A Long representing a bitmap of profiles that should be disabled when bluetooth starts. + * See {@link android.bluetooth.BluetoothProfile}. + * {@hide} + */ + public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles"; + + /** * The policy for deciding when Wi-Fi should go to sleep (which will in * turn switch to using the mobile data as an Internet connection). * <p> @@ -7693,10 +7700,12 @@ public final class Settings { * The following keys are supported: * * <pre> - * idle_duration (long) + * idle_duration2 (long) * wallclock_threshold (long) * parole_interval (long) * parole_duration (long) + * + * idle_duration (long) // This is deprecated and used to circumvent b/26355386. * </pre> * * <p> @@ -8574,6 +8583,13 @@ public final class Settings { * @hide */ public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync"; + + /** + * Whether to enable cellular on boot. + * The value 1 - enable, 0 - disable + * @hide + */ + public static final String ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot"; } /** diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index fa347b9..22ad634 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1130,20 +1130,31 @@ public abstract class Layout { */ public int getOffsetForHorizontal(int line, float horiz) { // TODO: use Paint.getOffsetForAdvance to avoid binary search - int max = getLineEnd(line) - 1; - int min = getLineStart(line); + final int lineEndOffset = getLineEnd(line); + final int lineStartOffset = getLineStart(line); + Directions dirs = getLineDirections(line); - if (line == getLineCount() - 1) - max++; + TextLine tl = TextLine.obtain(); + // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here. + tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs, + false, null); - int best = min; + final int max; + if (line == getLineCount() - 1) { + max = lineEndOffset; + } else { + max = tl.getOffsetToLeftRightOf(lineEndOffset - lineStartOffset, + !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset; + } + int best = lineStartOffset; float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz); for (int i = 0; i < dirs.mDirections.length; i += 2) { - int here = min + dirs.mDirections[i]; + int here = lineStartOffset + dirs.mDirections[i]; int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK); - int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1; + boolean isRtl = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0; + int swap = isRtl ? -1 : 1; if (there > max) there = max; @@ -1163,23 +1174,23 @@ public abstract class Layout { low = here + 1; if (low < there) { - low = getOffsetAtStartOf(low); - - float dist = Math.abs(getPrimaryHorizontal(low) - horiz); - - int aft = TextUtils.getOffsetAfter(mText, low); - if (aft < there) { - float other = Math.abs(getPrimaryHorizontal(aft) - horiz); - - if (other < dist) { - dist = other; - low = aft; + int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset; + low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset; + if (low >= here && low < there) { + float dist = Math.abs(getPrimaryHorizontal(low) - horiz); + if (aft < there) { + float other = Math.abs(getPrimaryHorizontal(aft) - horiz); + + if (other < dist) { + dist = other; + low = aft; + } } - } - if (dist < bestdist) { - bestdist = dist; - best = low; + if (dist < bestdist) { + bestdist = dist; + best = low; + } } } @@ -1198,6 +1209,7 @@ public abstract class Layout { best = max; } + TextLine.recycle(tl); return best; } diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 39e8694..3592187 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -718,13 +718,14 @@ class TextLine { * @param bottom the bottom of the line * @param fmi receives metrics information, can be null * @param needWidth true if the width of the run is needed + * @param offset the offset for the purpose of measuring * @return the signed width of the run based on the run direction; only * valid if needWidth is true */ private float handleText(TextPaint wp, int start, int end, int contextStart, int contextEnd, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, - FontMetricsInt fmi, boolean needWidth) { + FontMetricsInt fmi, boolean needWidth, int offset) { // Get metrics first (even for empty strings or "0" width runs) if (fmi != null) { @@ -742,11 +743,11 @@ class TextLine { if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { if (mCharsValid) { ret = wp.getRunAdvance(mChars, start, end, contextStart, contextEnd, - runIsRtl, end); + runIsRtl, offset); } else { int delta = mStart; ret = wp.getRunAdvance(mText, delta + start, delta + end, - delta + contextStart, delta + contextEnd, runIsRtl, delta + end); + delta + contextStart, delta + contextEnd, runIsRtl, delta + offset); } } @@ -895,8 +896,8 @@ class TextLine { TextPaint wp = mWorkPaint; wp.set(mPaint); final int mlimit = measureLimit; - return handleText(wp, start, mlimit, start, limit, runIsRtl, c, x, top, - y, bottom, fmi, needWidth || mlimit < measureLimit); + return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top, + y, bottom, fmi, needWidth || mlimit < measureLimit, mlimit); } mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit); @@ -940,13 +941,14 @@ class TextLine { } for (int j = i, jnext; j < mlimit; j = jnext) { - jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) - + jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) - mStart; + int offset = Math.min(jnext, mlimit); wp.set(mPaint); for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { // Intentionally using >= and <= as explained above - if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) || + if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + offset) || (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue; CharacterStyle span = mCharacterStyleSpanSet.spans[k]; @@ -958,7 +960,7 @@ class TextLine { wp.setHyphenEdit(0); } x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x, - top, y, bottom, fmi, needWidth || jnext < measureLimit); + top, y, bottom, fmi, needWidth || jnext < measureLimit, offset); } } diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 7642ed9..5f88c11 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -256,16 +256,13 @@ public final class InputDevice implements Parcelable { public static final int SOURCE_TOUCH_NAVIGATION = 0x00200000 | SOURCE_CLASS_NONE; /** - * The input source is a touch device whose motions should be interpreted as gestures. - * - * For example, an upward swipe should be treated the same as a swipe of the touchscreen. - * The same should apply for left, right, down swipes. Complex gestures may also be input. + * The input source is a rotating encoder device whose motions should be interpreted as akin to + * those of a scroll wheel. * * @see #SOURCE_CLASS_NONE - * - * @hide + * {@hide} */ - public static final int SOURCE_GESTURE_SENSOR = 0x00400000 | SOURCE_CLASS_NONE; + public static final int SOURCE_ROTARY_ENCODER = 0x00400000 | SOURCE_CLASS_NONE; /** * The input source is a joystick. @@ -284,6 +281,18 @@ public final class InputDevice implements Parcelable { public static final int SOURCE_HDMI = 0x02000000 | SOURCE_CLASS_BUTTON; /** + * The input source is a touch device whose motions should be interpreted as gestures. + * + * For example, an upward swipe should be treated the same as a swipe of the touchscreen. + * The same should apply for left, right, down swipes. Complex gestures may also be input. + * + * @see #SOURCE_CLASS_NONE + * + * @hide + */ + public static final int SOURCE_GESTURE_SENSOR = 0x10000000 | SOURCE_CLASS_NONE; + + /** * A special input source constant that is used when filtering input devices * to match devices that provide any type of input source. */ diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index d5847be..d128288 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -761,6 +761,19 @@ public class KeyEvent extends InputEvent implements Parcelable { * Backs out one level of a navigation hierarchy or collapses the item that currently has * focus. */ public static final int KEYCODE_NAVIGATE_OUT = 263; + /** Key code constant: Primary stem key for Wear + * Main power/reset button on watch. + * @hide */ + public static final int KEYCODE_STEM_PRIMARY = 264; + /** Key code constant: Generic stem key 1 for Wear + * @hide */ + public static final int KEYCODE_STEM_1 = 265; + /** Key code constant: Generic stem key 2 for Wear + * @hide */ + public static final int KEYCODE_STEM_2 = 266; + /** Key code constant: Generic stem key 3 for Wear + * @hide */ + public static final int KEYCODE_STEM_3 = 267; /** Key code constant: Skip forward media key. */ public static final int KEYCODE_MEDIA_SKIP_FORWARD = 272; /** Key code constant: Skip backward media key. */ @@ -771,8 +784,11 @@ public class KeyEvent extends InputEvent implements Parcelable { /** Key code constant: Step backward media key. * Steps media backward, one frame at a time. */ public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275; + /** Key code constant: put device to sleep unless a wakelock is held. + * @hide */ + public static final int KEYCODE_SOFT_SLEEP = 276; - private static final int LAST_KEYCODE = KEYCODE_MEDIA_STEP_BACKWARD; + private static final int LAST_KEYCODE = KEYCODE_SOFT_SLEEP; // NOTE: If you add a new keycode here you must also add it to: // isSystem() @@ -1836,6 +1852,9 @@ public class KeyEvent extends InputEvent implements Parcelable { case KeyEvent.KEYCODE_VOLUME_MUTE: case KeyEvent.KEYCODE_CAMERA: case KeyEvent.KEYCODE_FOCUS: + case KeyEvent.KEYCODE_STEM_1: + case KeyEvent.KEYCODE_STEM_2: + case KeyEvent.KEYCODE_STEM_3: return true; } return false; diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 6026d04..527d7e5 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -962,6 +962,22 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_TILT = 25; /** + * Axis constant: Generic scroll axis of a motion event. + * <p> + * <ul> + * <li>Reports the relative movement of the generic scrolling device. + * </ul> + * </p><p> + * This axis should be used for scroll events that are neither strictly vertical nor horizontal. + * A good example would be the rotation of a rotary encoder input device. + * </p> + * + * @see #getAxisValue(int, int) + * {@hide} + */ + public static final int AXIS_SCROLL = 26; + + /** * Axis constant: Generic 1 axis of a motion event. * The interpretation of a generic axis is device-specific. * @@ -1171,6 +1187,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { names.append(AXIS_BRAKE, "AXIS_BRAKE"); names.append(AXIS_DISTANCE, "AXIS_DISTANCE"); names.append(AXIS_TILT, "AXIS_TILT"); + names.append(AXIS_SCROLL, "AXIS_SCROLL"); names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1"); names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2"); names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3"); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 93345c2..4b56352 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -16940,8 +16940,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @CallSuper protected boolean verifyDrawable(Drawable who) { - return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who) - || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); + // Avoid verifying the scroll bar drawable so that we don't end up in + // an invalidation loop. This effectively prevents the scroll bar + // drawable from triggering invalidations and scheduling runnables. + return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 42402eb..9569422 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -174,6 +174,10 @@ public final class ViewRootImpl implements ViewParent, // so the window should no longer be active. boolean mStopped = false; + // Set to true if the owner of this window is in ambient mode, + // which means it won't receive input events. + boolean mIsAmbientMode = false; + // Set to true to stop input during an Activity Transition. boolean mPausedForTransition = false; @@ -990,6 +994,10 @@ public final class ViewRootImpl implements ViewParent, } } + public void setIsAmbientMode(boolean ambient) { + mIsAmbientMode = ambient; + } + void setWindowStopped(boolean stopped) { if (mStopped != stopped) { mStopped = stopped; @@ -3704,7 +3712,7 @@ public final class ViewRootImpl implements ViewParent, return true; } else if ((!mAttachInfo.mHasWindowFocus && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped - || (mPausedForTransition && !isBack(q.mEvent))) { + || mIsAmbientMode || (mPausedForTransition && !isBack(q.mEvent))) { // This is a focus event and the window doesn't currently have input focus or // has stopped. This could be an event that came back from the previous stage // but the window has lost focus or stopped in the meantime. @@ -5514,6 +5522,8 @@ public final class ViewRootImpl implements ViewParent, writer.println(mProcessInputEventsScheduled); writer.print(innerPrefix); writer.print("mTraversalScheduled="); writer.print(mTraversalScheduled); + writer.print(innerPrefix); writer.print("mIsAmbientMode="); + writer.print(mIsAmbientMode); if (mTraversalScheduled) { writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")"); } else { diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index b5e08ca..df3d850 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -348,7 +348,6 @@ public class LinearLayout extends ViewGroup { final int count = getVirtualChildCount(); for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); - if (child != null && child.getVisibility() != GONE) { if (hasDividerBeforeChildAt(i)) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); @@ -377,7 +376,7 @@ public class LinearLayout extends ViewGroup { */ private View getLastNonGoneChild() { for (int i = getVirtualChildCount() - 1; i >= 0; i--) { - View child = getVirtualChildAt(i); + final View child = getVirtualChildAt(i); if (child != null && child.getVisibility() != GONE) { return child; } @@ -390,7 +389,6 @@ public class LinearLayout extends ViewGroup { final boolean isLayoutRtl = isLayoutRtl(); for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); - if (child != null && child.getVisibility() != GONE) { if (hasDividerBeforeChildAt(i)) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); @@ -577,8 +575,9 @@ public class LinearLayout extends ViewGroup { * for an example.</p> * * @param index the child's index - * @return the child at the specified index + * @return the child at the specified index, may be {@code null} */ + @Nullable View getVirtualChildAt(int index) { return getChildAt(index); } @@ -659,7 +658,7 @@ public class LinearLayout extends ViewGroup { */ private boolean allViewsAreGoneBefore(int childIndex) { for (int i = childIndex - 1; i >= 0; i--) { - View child = getVirtualChildAt(i); + final View child = getVirtualChildAt(i); if (child != null && child.getVisibility() != GONE) { return false; } @@ -703,7 +702,6 @@ public class LinearLayout extends ViewGroup { // See how tall everyone is. Also remember max width. for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); - if (child == null) { mTotalLength += measureNullChild(i); continue; @@ -822,7 +820,6 @@ public class LinearLayout extends ViewGroup { for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); - if (child == null) { mTotalLength += measureNullChild(i); continue; @@ -938,7 +935,6 @@ public class LinearLayout extends ViewGroup { if (useLargestChild && heightMode != MeasureSpec.EXACTLY) { for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); - if (child == null || child.getVisibility() == View.GONE) { continue; } @@ -981,7 +977,7 @@ public class LinearLayout extends ViewGroup { MeasureSpec.EXACTLY); for (int i = 0; i< count; ++i) { final View child = getVirtualChildAt(i); - if (child.getVisibility() != GONE) { + if (child != null && child.getVisibility() != GONE) { LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams()); if (lp.width == LayoutParams.MATCH_PARENT) { @@ -1047,7 +1043,6 @@ public class LinearLayout extends ViewGroup { // See how wide everyone is. Also remember max height. for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); - if (child == null) { mTotalLength += measureNullChild(i); continue; @@ -1203,7 +1198,6 @@ public class LinearLayout extends ViewGroup { for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); - if (child == null) { mTotalLength += measureNullChild(i); continue; @@ -1361,7 +1355,6 @@ public class LinearLayout extends ViewGroup { if (useLargestChild && widthMode != MeasureSpec.EXACTLY) { for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); - if (child == null || child.getVisibility() == View.GONE) { continue; } @@ -1406,7 +1399,7 @@ public class LinearLayout extends ViewGroup { MeasureSpec.EXACTLY); for (int i = 0; i < count; ++i) { final View child = getVirtualChildAt(i); - if (child.getVisibility() != GONE) { + if (child != null && child.getVisibility() != GONE) { LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); if (lp.height == LayoutParams.MATCH_PARENT) { @@ -1666,9 +1659,8 @@ public class LinearLayout extends ViewGroup { } for (int i = 0; i < count; i++) { - int childIndex = start + dir * i; + final int childIndex = start + dir * i; final View child = getVirtualChildAt(childIndex); - if (child == null) { childLeft += measureNullChild(childIndex); } else if (child.getVisibility() != GONE) { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 6c9c0e3..6a272e5 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -55,6 +56,8 @@ import android.view.ViewGroup; import android.widget.AdapterView.OnItemClickListener; import libcore.util.Objects; +import com.android.internal.R; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -206,14 +209,22 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public static class OnClickHandler { + + private int mEnterAnimationId; + public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { try { // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? Context context = view.getContext(); - ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, - 0, 0, - view.getMeasuredWidth(), view.getMeasuredHeight()); + ActivityOptions opts; + if (mEnterAnimationId != 0) { + opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0); + } else { + opts = ActivityOptions.makeScaleUpAnimation(view, + 0, 0, + view.getMeasuredWidth(), view.getMeasuredHeight()); + } context.startIntentSender( pendingIntent.getIntentSender(), fillInIntent, Intent.FLAG_ACTIVITY_NEW_TASK, @@ -228,6 +239,10 @@ public class RemoteViews implements Parcelable, Filter { } return true; } + + public void setEnterAnimationId(int enterAnimationId) { + mEnterAnimationId = enterAnimationId; + } } /** @@ -2767,11 +2782,31 @@ public class RemoteViews implements Parcelable, Filter { inflater.setFilter(this); result = inflater.inflate(rvToApply.getLayoutId(), parent, false); + loadTransitionOverride(context, handler); + rvToApply.performApply(result, parent, handler); return result; } + private static void loadTransitionOverride(Context context, + RemoteViews.OnClickHandler handler) { + if (handler != null && context.getResources().getBoolean( + com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) { + TypedArray windowStyle = context.getTheme().obtainStyledAttributes( + com.android.internal.R.styleable.Window); + int windowAnimations = windowStyle.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + TypedArray windowAnimationStyle = context.obtainStyledAttributes( + windowAnimations, com.android.internal.R.styleable.WindowAnimation); + handler.setEnterAnimationId(windowAnimationStyle.getResourceId( + com.android.internal.R.styleable. + WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0)); + windowStyle.recycle(); + windowAnimationStyle.recycle(); + } + } + /** * Applies all of the actions to the provided view. * diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java index f7f9c91..22931fc 100644 --- a/core/java/android/widget/TableRow.java +++ b/core/java/android/widget/TableRow.java @@ -98,7 +98,7 @@ public class TableRow extends LinearLayout { * {@hide} */ void setColumnCollapsed(int columnIndex, boolean collapsed) { - View child = getVirtualChildAt(columnIndex); + final View child = getVirtualChildAt(columnIndex); if (child != null) { child.setVisibility(collapsed ? GONE : VISIBLE); } |