diff options
Diffstat (limited to 'core/java')
30 files changed, 520 insertions, 155 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index d65b490..e18aa5c 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -537,8 +537,7 @@ public class ValueAnimator extends Animator { * @param playTime The time, in milliseconds, to which the animation is advanced or rewound. */ public void setCurrentPlayTime(long playTime) { - float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : - playTime == 0 ? 0 : 1; + float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1; setCurrentFraction(fraction); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b64e724..6b4db10 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2436,7 +2436,7 @@ public final class ActivityThread { private void deliverNewIntents(ActivityClientRecord r, List<ReferrerIntent> intents) { final int N = intents.size(); for (int i=0; i<N; i++) { - Intent intent = intents.get(i); + ReferrerIntent intent = intents.get(i); intent.setExtrasClassLoader(r.activity.getClassLoader()); intent.prepareToEnterProcess(); r.activity.mFragments.noteStateNotSaved(); diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index d96153a..3c30404 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1208,14 +1208,17 @@ public class Instrumentation { * @param intent The new intent being received. */ public void callActivityOnNewIntent(Activity activity, Intent intent) { + activity.onNewIntent(intent); + } + + /** + * @hide + */ + public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent) { final String oldReferrer = activity.mReferrer; try { - try { - activity.mReferrer = ((ReferrerIntent)intent).mReferrer; - } catch (ClassCastException e) { - activity.mReferrer = null; - } - activity.onNewIntent(intent); + activity.mReferrer = intent.mReferrer; + callActivityOnNewIntent(activity, new Intent(intent)); } finally { activity.mReferrer = oldReferrer; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 9e8a793..8dce59a 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1736,6 +1736,7 @@ public class Notification implements Parcelable builder.setSound(this.sound, this.audioStreamType); builder.setDefaults(this.defaults); builder.setVibrate(this.vibrate); + builder.setDeleteIntent(this.deleteIntent); // now apply the latestEventInfo fields if (contentTitle != null) { diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index 6454367..3a2c21b 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -134,6 +134,9 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, mTimePicker.getCurrentMinute()); } break; + case BUTTON_NEGATIVE: + cancel(); + break; } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 50d6b11..53e0896 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1485,8 +1485,8 @@ public class DevicePolicyManager { * Flag for {@link #wipeData(int)}: also erase the factory reset protection * data. * - * This flag may only be set by device owner admins; if it is set by other - * admins a {@link SecurityException} will be thrown. + * <p>This flag may only be set by device owner admins; if it is set by + * other admins a {@link SecurityException} will be thrown. */ public static final int WIPE_RESET_PROTECTION_DATA = 0x0002; diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java index e94a8ce..f451340 100644 --- a/core/java/android/bluetooth/BluetoothGattServer.java +++ b/core/java/android/bluetooth/BluetoothGattServer.java @@ -284,6 +284,24 @@ public final class BluetoothGattServer implements BluetoothProfile { Log.w(TAG, "Unhandled exception: " + ex); } } + + /** + * The MTU for a connection has changed + * @hide + */ + public void onMtuChanged(String address, int mtu) { + if (DBG) Log.d(TAG, "onMtuChanged() - " + + "device=" + address + ", mtu=" + mtu); + + BluetoothDevice device = mAdapter.getRemoteDevice(address); + if (device == null) return; + + try { + mCallback.onMtuChanged(device, mtu); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } }; /** diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java index 1dd06f2..2afcf9a 100644 --- a/core/java/android/bluetooth/BluetoothGattServerCallback.java +++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java @@ -145,4 +145,16 @@ public abstract class BluetoothGattServerCallback { */ public void onNotificationSent(BluetoothDevice device, int status) { } + + /** + * Callback indicating the MTU for a given device connection has changed. + * + * <p>This callback will be invoked if a remote client has requested to change + * the MTU for a given connection. + * + * @param device The remote device that requested the MTU change + * @param mtu The new MTU size + */ + public void onMtuChanged(BluetoothDevice device, int mtu) { + } } diff --git a/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl b/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl index 5d4d6c6..8b202b2 100644 --- a/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl @@ -59,4 +59,5 @@ oneway interface IBluetoothGattServerCallback { in byte[] value); void onExecuteWrite(in String address, in int transId, in boolean execWrite); void onNotificationSent(in String address, in int status); + void onMtuChanged(in String address, in int mtu); } diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index ecae52c..a176593 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -627,7 +627,21 @@ public final class AssetManager implements AutoCloseable { * * {@hide} */ - public native final int addOverlayPath(String idmapPath); + + public final int addOverlayPath(String idmapPath) { + synchronized (this) { + int res = addOverlayPathNative(idmapPath); + makeStringBlocks(mStringBlocks); + return res; + } + } + + /** + * See addOverlayPath. + * + * {@hide} + */ + public native final int addOverlayPathNative(String idmapPath); /** * Add multiple sets of assets to the asset manager at once. See diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 78d3e9c..73913b6 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -744,7 +744,10 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. * @see #getDrawable(int, Theme) + * @deprecated Use {@link #getDrawable(int, Theme)} instead. */ + @Deprecated + @Nullable public Drawable getDrawable(int id) throws NotFoundException { final Drawable d = getDrawable(id, null); if (d != null && d.canApplyTheme()) { @@ -769,6 +772,7 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. */ + @Nullable public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException { TypedValue value; synchronized (mAccessLock) { @@ -813,7 +817,10 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. * @see #getDrawableForDensity(int, int, Theme) + * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead. */ + @Deprecated + @Nullable public Drawable getDrawableForDensity(int id, int density) throws NotFoundException { return getDrawableForDensity(id, density, null); } @@ -832,6 +839,7 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. */ + @Nullable public Drawable getDrawableForDensity(int id, int density, @Nullable Theme theme) { TypedValue value; synchronized (mAccessLock) { diff --git a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl index a16e878..c708d20 100644 --- a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl +++ b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl @@ -22,7 +22,7 @@ package android.hardware.hdmi; * * @hide */ -oneway interface IHdmiVendorCommandListener { +interface IHdmiVendorCommandListener { void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId); void onControlStateChanged(boolean enabled, int reason); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index d4242ef..5da1b4b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -71,7 +71,6 @@ import libcore.net.event.NetworkEventDispatcher; */ public class ConnectivityManager { private static final String TAG = "ConnectivityManager"; - private static final boolean LEGACY_DBG = true; // STOPSHIP /** * A change in network connectivity has occurred. A default connection has either @@ -882,14 +881,6 @@ public class ConnectivityManager { NetworkRequest request = null; synchronized (sLegacyRequests) { - if (LEGACY_DBG) { - Log.d(TAG, "Looking for legacyRequest for netCap with hash: " + netCap + " (" + - netCap.hashCode() + ")"); - Log.d(TAG, "sLegacyRequests has:"); - for (NetworkCapabilities nc : sLegacyRequests.keySet()) { - Log.d(TAG, " " + nc + " (" + nc.hashCode() + ")"); - } - } LegacyRequest l = sLegacyRequests.get(netCap); if (l != null) { Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 4709443..11fc69e 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -91,11 +91,6 @@ public abstract class BatteryStats implements Parcelable { public static final int WIFI_MULTICAST_ENABLED = 7; /** - * A constant indicating an audio turn on timer - */ - public static final int AUDIO_TURNED_ON = 7; - - /** * A constant indicating a video turn on timer */ public static final int VIDEO_TURNED_ON = 8; @@ -131,6 +126,11 @@ public abstract class BatteryStats implements Parcelable { public static final int JOB = 14; /** + * A constant indicating an audio turn on timer + */ + public static final int AUDIO_TURNED_ON = 15; + + /** * Include all of the data in the stats, including previously saved data. */ public static final int STATS_SINCE_CHARGED = 0; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index fe47f5b..0a724a1 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -17,9 +17,8 @@ package android.os; import android.system.ErrnoException; -import android.text.TextUtils; import android.system.Os; -import android.system.OsConstants; +import android.text.TextUtils; import android.util.Log; import android.util.Slog; @@ -403,20 +402,89 @@ public class FileUtils { return success; } + private static boolean isValidExtFilenameChar(char c) { + switch (c) { + case '\0': + case '/': + return false; + default: + return true; + } + } + /** - * Assert that given filename is valid on ext4. + * Check if given filename is valid for an ext4 filesystem. */ public static boolean isValidExtFilename(String name) { + return (name != null) && name.equals(buildValidExtFilename(name)); + } + + /** + * Mutate the given filename to make it valid for an ext4 filesystem, + * replacing any invalid characters with "_". + */ + public static String buildValidExtFilename(String name) { if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { - return false; + return "(invalid)"; } + final StringBuilder res = new StringBuilder(name.length()); for (int i = 0; i < name.length(); i++) { final char c = name.charAt(i); - if (c == '\0' || c == '/') { + if (isValidExtFilenameChar(c)) { + res.append(c); + } else { + res.append('_'); + } + } + return res.toString(); + } + + private static boolean isValidFatFilenameChar(char c) { + if ((0x00 <= c && c <= 0x1f)) { + return false; + } + switch (c) { + case '"': + case '*': + case '/': + case ':': + case '<': + case '>': + case '?': + case '\\': + case '|': + case 0x7F: return false; + default: + return true; + } + } + + /** + * Check if given filename is valid for a FAT filesystem. + */ + public static boolean isValidFatFilename(String name) { + return (name != null) && name.equals(buildValidFatFilename(name)); + } + + /** + * Mutate the given filename to make it valid for a FAT filesystem, + * replacing any invalid characters with "_". + */ + public static String buildValidFatFilename(String name) { + if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) { + return "(invalid)"; + } + final StringBuilder res = new StringBuilder(name.length()); + for (int i = 0; i < name.length(); i++) { + final char c = name.charAt(i); + if (isValidFatFilenameChar(c)) { + res.append(c); + } else { + res.append('_'); } } - return true; + return res.toString(); } public static String rewriteAfterRename(File beforeDir, File afterDir, String path) { diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index c6b2151..4e8ec89 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -395,10 +395,17 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * connected to each other. The two sockets are indistinguishable. */ public static ParcelFileDescriptor[] createSocketPair() throws IOException { + return createSocketPair(SOCK_STREAM); + } + + /** + * @hide + */ + public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException { try { final FileDescriptor fd0 = new FileDescriptor(); final FileDescriptor fd1 = new FileDescriptor(); - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1); + Os.socketpair(AF_UNIX, type, 0, fd0, fd1); return new ParcelFileDescriptor[] { new ParcelFileDescriptor(fd0), new ParcelFileDescriptor(fd1) }; @@ -417,11 +424,18 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * This can also be used to detect remote crashes. */ public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { + return createReliableSocketPair(SOCK_STREAM); + } + + /** + * @hide + */ + public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException { try { final FileDescriptor[] comm = createCommSocketPair(); final FileDescriptor fd0 = new FileDescriptor(); final FileDescriptor fd1 = new FileDescriptor(); - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1); + Os.socketpair(AF_UNIX, type, 0, fd0, fd1); return new ParcelFileDescriptor[] { new ParcelFileDescriptor(fd0, comm[0]), new ParcelFileDescriptor(fd1, comm[1]) }; diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index cf407f4..116110e 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -856,6 +856,38 @@ public interface IMountService extends IInterface { } return _result; } + + @Override + public long lastMaintenance() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + long _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_lastMaintenance, _data, _reply, 0); + _reply.readException(); + _result = _reply.readLong(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + + @Override + public void runMaintenance() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_runMaintenance, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return; + } } private static final String DESCRIPTOR = "IMountService"; @@ -942,6 +974,10 @@ public interface IMountService extends IInterface { static final int TRANSACTION_resizeSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 40; + static final int TRANSACTION_lastMaintenance = IBinder.FIRST_CALL_TRANSACTION + 41; + + static final int TRANSACTION_runMaintenance = IBinder.FIRST_CALL_TRANSACTION + 42; + /** * Cast an IBinder object into an IMountService interface, generating a * proxy if needed. @@ -1347,6 +1383,19 @@ public interface IMountService extends IInterface { reply.writeInt(resultCode); return true; } + case TRANSACTION_lastMaintenance: { + data.enforceInterface(DESCRIPTOR); + long lastMaintenance = lastMaintenance(); + reply.writeNoException(); + reply.writeLong(lastMaintenance); + return true; + } + case TRANSACTION_runMaintenance: { + data.enforceInterface(DESCRIPTOR); + runMaintenance(); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); } @@ -1617,4 +1666,18 @@ public interface IMountService extends IInterface { public String getField(String field) throws RemoteException; public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException; + + /** + * Report the time of the last maintenance operation such as fstrim. + * @return Timestamp of the last maintenance operation, in the + * System.currentTimeMillis() time base + * @throws RemoteException + */ + public long lastMaintenance() throws RemoteException; + + /** + * Kick off an immediate maintenance operation + * @throws RemoteException + */ + public void runMaintenance() throws RemoteException; } diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 3130b64..c3dd4ce 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -44,6 +44,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba public interface Callback { void onSampleStarting(SeekBarVolumizer sbv); + void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch); + void onMuted(boolean muted); } private final Context mContext; @@ -53,6 +55,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private final AudioManager mAudioManager; private final int mStreamType; private final int mMaxStreamVolume; + private boolean mAffectedByRingerMode; + private boolean mNotificationOrRing; private final Receiver mReceiver = new Receiver(); private Handler mHandler; @@ -60,8 +64,10 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private int mOriginalStreamVolume; private Ringtone mRingtone; private int mLastProgress = -1; + private boolean mMuted; private SeekBar mSeekBar; private int mVolumeBeforeMute = -1; + private int mRingerMode; private static final int MSG_SET_STREAM_VOLUME = 0; private static final int MSG_START_SAMPLE = 1; @@ -69,14 +75,22 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private static final int MSG_INIT_SAMPLE = 3; private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000; - public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, - Callback callback) { + public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) { mContext = context; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mStreamType = streamType; + mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType); + mNotificationOrRing = isNotificationOrRing(mStreamType); + if (mNotificationOrRing) { + mRingerMode = mAudioManager.getRingerModeInternal(); + } mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType); mCallback = callback; mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType); + mMuted = mAudioManager.isStreamMute(mStreamType); + if (mCallback != null) { + mCallback.onMuted(mMuted); + } if (defaultUri == null) { if (mStreamType == AudioManager.STREAM_RING) { defaultUri = Settings.System.DEFAULT_RINGTONE_URI; @@ -89,6 +103,10 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mDefaultUri = defaultUri; } + private static boolean isNotificationOrRing(int stream) { + return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION; + } + public void setSeekBar(SeekBar seekBar) { if (mSeekBar != null) { mSeekBar.setOnSeekBarChangeListener(null); @@ -96,10 +114,23 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mSeekBar = seekBar; mSeekBar.setOnSeekBarChangeListener(null); mSeekBar.setMax(mMaxStreamVolume); - mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume); + updateSeekBar(); mSeekBar.setOnSeekBarChangeListener(this); } + protected void updateSeekBar() { + if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { + mSeekBar.setEnabled(true); + mSeekBar.setProgress(0); + } else if (mMuted) { + mSeekBar.setEnabled(false); + mSeekBar.setProgress(0); + } else { + mSeekBar.setEnabled(true); + mSeekBar.setProgress(mLastProgress > -1 ? mLastProgress : mOriginalStreamVolume); + } + } + @Override public boolean handleMessage(Message msg) { switch (msg.what) { @@ -193,13 +224,13 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0); } - public void onProgressChanged(SeekBar seekBar, int progress, - boolean fromTouch) { - if (!fromTouch) { - return; + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { + if (fromTouch) { + postSetVolume(progress); + } + if (mCallback != null) { + mCallback.onProgressChanged(seekBar, progress, fromTouch); } - - postSetVolume(progress); } private void postSetVolume(int progress) { @@ -276,14 +307,29 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba public void handleMessage(Message msg) { if (msg.what == UPDATE_SLIDER) { if (mSeekBar != null) { - mSeekBar.setProgress(msg.arg1); - mLastProgress = mSeekBar.getProgress(); + mLastProgress = msg.arg1; + final boolean muted = msg.arg2 != 0; + if (muted != mMuted) { + mMuted = muted; + if (mCallback != null) { + mCallback.onMuted(mMuted); + } + } + updateSeekBar(); } } } - public void postUpdateSlider(int volume) { - obtainMessage(UPDATE_SLIDER, volume, 0).sendToTarget(); + public void postUpdateSlider(int volume, boolean mute) { + obtainMessage(UPDATE_SLIDER, volume, mute ? 1 : 0).sendToTarget(); + } + } + + private void updateSlider() { + if (mSeekBar != null && mAudioManager != null) { + final int volume = mAudioManager.getStreamVolume(mStreamType); + final boolean mute = mAudioManager.isStreamMute(mStreamType); + mUiHandler.postUpdateSlider(volume, mute); } } @@ -295,10 +341,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - if (mSeekBar != null && mAudioManager != null) { - final int volume = mAudioManager.getStreamVolume(mStreamType); - mUiHandler.postUpdateSlider(volume); - } + updateSlider(); } } @@ -310,6 +353,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mListening = listening; if (listening) { final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); + filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); mContext.registerReceiver(this, filter); } else { mContext.unregisterReceiver(this); @@ -318,11 +362,23 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba @Override public void onReceive(Context context, Intent intent) { - if (!AudioManager.VOLUME_CHANGED_ACTION.equals(intent.getAction())) return; - final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - final int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); - if (mSeekBar != null && streamType == mStreamType && streamValue != -1) { - mUiHandler.postUpdateSlider(streamValue); + final String action = intent.getAction(); + if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { + int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); + final boolean streamMatch = mNotificationOrRing ? isNotificationOrRing(streamType) + : (streamType == mStreamType); + if (mSeekBar != null && streamMatch && streamValue != -1) { + final boolean muted = mAudioManager.isStreamMute(mStreamType); + mUiHandler.postUpdateSlider(streamValue, muted); + } + } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { + if (mNotificationOrRing) { + mRingerMode = mAudioManager.getRingerModeInternal(); + } + if (mAffectedByRingerMode) { + updateSlider(); + } } } } diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index 0d4c0b6..a2da01b 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -150,6 +150,16 @@ public class VolumePreference extends SeekBarDialogPreference implements } @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { + // noop + } + + @Override + public void onMuted(boolean muted) { + // noop + } + + @Override protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState(); if (isPersistent()) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bf91b3e..345a5b1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5550,6 +5550,13 @@ public final class Settings { public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs"; /** + * Time since last fstrim (milliseconds) after which we force one to happen + * during device startup. If unset, the default is 3 days. + * @hide + */ + public static final String FSTRIM_MANDATORY_INTERVAL = "fstrim_mandatory_interval"; + + /** * The interval in milliseconds at which to check packet counts on the * mobile data interface when screen is on, to detect possible data * connection problems. diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java index 3a91d1a..80bdbf1 100644 --- a/core/java/android/service/notification/Condition.java +++ b/core/java/android/service/notification/Condition.java @@ -160,7 +160,7 @@ public class Condition implements Parcelable { } public static boolean isValidId(Uri id, String pkg) { - return id != null && id.getScheme().equals(SCHEME) && id.getAuthority().equals(pkg); + return id != null && SCHEME.equals(id.getScheme()) && pkg.equals(id.getAuthority()); } public static final Parcelable.Creator<Condition> CREATOR diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 56a05fe..9feb681 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -59,6 +59,11 @@ public final class DisplayInfo implements Parcelable { public String name; /** + * Unique identifier for the display. Shouldn't be displayed to the user. + */ + public String uniqueId; + + /** * The width of the portion of the display that is available to applications, in pixels. * Represents the size of the display minus any system decorations. */ @@ -257,7 +262,7 @@ public final class DisplayInfo implements Parcelable { && flags == other.flags && type == other.type && Objects.equal(address, other.address) - && Objects.equal(name, other.name) + && Objects.equal(uniqueId, other.uniqueId) && appWidth == other.appWidth && appHeight == other.appHeight && smallestNominalAppWidth == other.smallestNominalAppWidth @@ -293,6 +298,7 @@ public final class DisplayInfo implements Parcelable { type = other.type; address = other.address; name = other.name; + uniqueId = other.uniqueId; appWidth = other.appWidth; appHeight = other.appHeight; smallestNominalAppWidth = other.smallestNominalAppWidth; @@ -348,6 +354,7 @@ public final class DisplayInfo implements Parcelable { state = source.readInt(); ownerUid = source.readInt(); ownerPackageName = source.readString(); + uniqueId = source.readString(); } @Override @@ -380,6 +387,7 @@ public final class DisplayInfo implements Parcelable { dest.writeInt(state); dest.writeInt(ownerUid); dest.writeString(ownerPackageName); + dest.writeString(uniqueId); } @Override @@ -445,6 +453,8 @@ public final class DisplayInfo implements Parcelable { StringBuilder sb = new StringBuilder(); sb.append("DisplayInfo{\""); sb.append(name); + sb.append("\", uniqueId \""); + sb.append(uniqueId); sb.append("\", app "); sb.append(appWidth); sb.append(" x "); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index abf23fc..512ea99 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5033,8 +5033,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.getMatrix().mapRect(rect); } - int dx = child.mLeft - mScrollX; - int dy = child.mTop - mScrollY; + final int dx = child.mLeft - mScrollX; + final int dy = child.mTop - mScrollY; rect.offset(dx, dy); @@ -5052,21 +5052,23 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager offset.y += dy; } + final int width = mRight - mLeft; + final int height = mBottom - mTop; + boolean rectIsVisible = true; if (mParent instanceof ViewGroup && ((ViewGroup)mParent).getClipChildren()) { - // clipChildren clips to the child's bounds - rectIsVisible = rect.intersect(0, 0, mRight - mLeft, mBottom - mTop); + // Clip to bounds. + rectIsVisible = rect.intersect(0, 0, width, height); } if (rectIsVisible && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) { - // Clip to padding + // Clip to padding. rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop, - mRight - mLeft - mPaddingLeft - mPaddingRight, - mBottom - mTop - mPaddingTop - mPaddingBottom); + width - mPaddingRight, height - mPaddingBottom); } if (rectIsVisible && mClipBounds != null) { - // Clip to clipBounds + // Clip to clipBounds. rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right, mClipBounds.bottom); } diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java index 0cf9ddd..5e5ef29 100644 --- a/core/java/android/view/ViewOverlay.java +++ b/core/java/android/view/ViewOverlay.java @@ -130,8 +130,11 @@ public class ViewOverlay { super(context); mHostView = hostView; mAttachInfo = mHostView.mAttachInfo; + mRight = hostView.getWidth(); mBottom = hostView.getHeight(); + // pass right+bottom directly to RenderNode, since not going through setters + mRenderNode.setLeftTopRightBottom(0, 0, mRight, mBottom); } public void add(Drawable drawable) { diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 4800c7f..a3ce808 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -695,19 +695,20 @@ public abstract class AbsSeekBar extends ProgressBar { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (isEnabled()) { - int progress = getProgress(); + int increment = mKeyProgressIncrement; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: - if (progress <= 0) break; - setProgress(progress - mKeyProgressIncrement, true); - onKeyChange(); - return true; - + increment = -increment; + // fallthrough case KeyEvent.KEYCODE_DPAD_RIGHT: - if (progress >= getMax()) break; - setProgress(progress + mKeyProgressIncrement, true); - onKeyChange(); - return true; + increment = isLayoutRtl() ? -increment : increment; + int progress = getProgress() + increment; + if (progress > 0 && progress < getMax()) { + setProgress(progress, true); + onKeyChange(); + return true; + } + break; } } diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 8b01dde..04b5616 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -1200,69 +1200,87 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { return degrees; } + boolean mChangedDuringTouch = false; + @Override public boolean onTouch(View v, MotionEvent event) { - if(!mInputEnabled) { + if (!mInputEnabled) { return true; } - final float eventX = event.getX(); - final float eventY = event.getY(); - - int degrees; - int snapDegrees; - boolean result = false; - - switch(event.getAction()) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_MOVE: - degrees = getDegreesFromXY(eventX, eventY); - if (degrees != -1) { - snapDegrees = (mShowHours ? - snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; - if (mShowHours) { - mSelectionDegrees[HOURS] = snapDegrees; - mSelectionDegrees[HOURS_INNER] = snapDegrees; - } else { - mSelectionDegrees[MINUTES] = snapDegrees; - } - performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - if (mListener != null) { - if (mShowHours) { - mListener.onValueSelected(HOURS, getCurrentHour(), false); - } else { - mListener.onValueSelected(MINUTES, getCurrentMinute(), false); - } - } - result = true; - invalidate(); + final int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_MOVE + || action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_DOWN) { + boolean forceSelection = false; + boolean autoAdvance = false; + + if (action == MotionEvent.ACTION_DOWN) { + // This is a new event stream, reset whether the value changed. + mChangedDuringTouch = false; + } else if (action == MotionEvent.ACTION_UP) { + autoAdvance = true; + + // If we saw a down/up pair without the value changing, assume + // this is a single-tap selection and force a change. + if (!mChangedDuringTouch) { + forceSelection = true; } - break; + } - case MotionEvent.ACTION_UP: - degrees = getDegreesFromXY(eventX, eventY); - if (degrees != -1) { - snapDegrees = (mShowHours ? - snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; - if (mShowHours) { - mSelectionDegrees[HOURS] = snapDegrees; - mSelectionDegrees[HOURS_INNER] = snapDegrees; - } else { - mSelectionDegrees[MINUTES] = snapDegrees; - } - if (mListener != null) { - if (mShowHours) { - mListener.onValueSelected(HOURS, getCurrentHour(), true); - } else { - mListener.onValueSelected(MINUTES, getCurrentMinute(), true); - } - } - invalidate(); - result = true; - } - break; + mChangedDuringTouch |= handleTouchInput( + event.getX(), event.getY(), forceSelection, autoAdvance); + } + + return true; + } + + private boolean handleTouchInput( + float x, float y, boolean forceSelection, boolean autoAdvance) { + // Calling getDegreesFromXY has side effects, so cache + // whether we used to be on the inner circle. + final boolean wasOnInnerCircle = mIsOnInnerCircle; + final int degrees = getDegreesFromXY(x, y); + if (degrees == -1) { + return false; } - return result; + + final int[] selectionDegrees = mSelectionDegrees; + int type = -1; + int newValue = -1; + + if (mShowHours) { + final int snapDegrees = snapOnly30s(degrees, 0) % 360; + if (forceSelection + || selectionDegrees[HOURS] != snapDegrees + || selectionDegrees[HOURS_INNER] != snapDegrees + || wasOnInnerCircle != mIsOnInnerCircle) { + selectionDegrees[HOURS] = snapDegrees; + selectionDegrees[HOURS_INNER] = snapDegrees; + + type = HOURS; + newValue = getCurrentHour(); + } + } else { + final int snapDegrees = snapPrefer30s(degrees) % 360; + if (forceSelection || selectionDegrees[MINUTES] != snapDegrees) { + selectionDegrees[MINUTES] = snapDegrees; + + type = MINUTES; + newValue = getCurrentMinute(); + } + } + + if (newValue != -1) { + if (mListener != null) { + mListener.onValueSelected(type, newValue, autoAdvance); + } + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + invalidate(); + return true; + } + + return false; } @Override diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 2db466a..634d03d 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -95,12 +95,14 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic private ListView mListView; private Button mAlwaysButton; private Button mOnceButton; + private View mProfileView; private int mIconDpi; private int mIconSize; private int mMaxColumns; private int mLastSelected = ListView.INVALID_POSITION; private boolean mResolvingHome = false; private int mProfileSwitchMessageId = -1; + private Intent mIntent; private UsageStatsManager mUsm; private Map<String, UsageStats> mStats; @@ -110,6 +112,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override public void onSomePackagesChanged() { mAdapter.handlePackagesChanged(); + if (mProfileView != null) { + bindProfileView(); + } } }; @@ -217,7 +222,6 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD; mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis()); - Log.d(TAG, "sinceTime=" + sinceTime); mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns); @@ -228,7 +232,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic mIconDpi = am.getLauncherLargeIconDensity(); mIconSize = am.getLauncherLargeIconSize(); - mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList, + mIntent = new Intent(intent); + mAdapter = new ResolveListAdapter(this, initialIntents, rList, mLaunchedFromUid, alwaysUseOption); final int layoutId; @@ -324,6 +329,40 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false); mOnceButton.setEnabled(true); } + + mProfileView = findViewById(R.id.profile_button); + if (mProfileView != null) { + mProfileView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final DisplayResolveInfo dri = mAdapter.getOtherProfile(); + if (dri == null) { + return; + } + + final Intent intent = intentForDisplayResolveInfo(dri); + onIntentSelected(dri.ri, intent, mAlwaysUseOption); + finish(); + } + }); + bindProfileView(); + } + } + + void bindProfileView() { + final DisplayResolveInfo dri = mAdapter.getOtherProfile(); + if (dri != null) { + mProfileView.setVisibility(View.VISIBLE); + final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon); + final TextView text = (TextView) mProfileView.findViewById(R.id.text1); + if (dri.displayIcon == null) { + new LoadIconTask().execute(dri); + } + icon.setImageDrawable(dri.displayIcon); + text.setText(dri.displayLabel); + } else { + mProfileView.setVisibility(View.GONE); + } } private void setProfileSwitchMessageId(int contentUserHint) { @@ -416,6 +455,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic mRegistered = true; } mAdapter.handlePackagesChanged(); + if (mProfileView != null) { + bindProfileView(); + } } @Override @@ -702,6 +744,17 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic startActivity(in); } + Intent intentForDisplayResolveInfo(DisplayResolveInfo dri) { + Intent intent = new Intent(dri.origIntent != null ? dri.origIntent : + getReplacementIntent(dri.ri.activityInfo, mIntent)); + intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT + |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); + ActivityInfo ai = dri.ri.activityInfo; + intent.setComponent(new ComponentName( + ai.applicationInfo.packageName, ai.name)); + return intent; + } + private final class DisplayResolveInfo { ResolveInfo ri; CharSequence displayLabel; @@ -722,7 +775,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic private final Intent[] mInitialIntents; private final List<ResolveInfo> mBaseResolveList; private ResolveInfo mLastChosen; - private final Intent mIntent; + private DisplayResolveInfo mOtherProfile; private final int mLaunchedFromUid; private final LayoutInflater mInflater; @@ -732,10 +785,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic private int mLastChosenPosition = -1; private boolean mFilterLastUsed; - public ResolveListAdapter(Context context, Intent intent, - Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid, - boolean filterLastUsed) { - mIntent = new Intent(intent); + public ResolveListAdapter(Context context, Intent[] initialIntents, + List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) { mInitialIntents = initialIntents; mBaseResolveList = rList; mLaunchedFromUid = launchedFromUid; @@ -764,6 +815,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic return null; } + public DisplayResolveInfo getOtherProfile() { + return mOtherProfile; + } + public int getFilteredPosition() { if (mFilterLastUsed && mLastChosenPosition >= 0) { return mLastChosenPosition; @@ -870,7 +925,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic ri.nonLocalizedLabel = li.getNonLocalizedLabel(); ri.icon = li.getIconResource(); } - mList.add(new DisplayResolveInfo(ri, + addResolveInfo(new DisplayResolveInfo(ri, ri.loadLabel(getPackageManager()), null, ii)); } } @@ -915,7 +970,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic mLastChosenPosition = mList.size(); } // No duplicate labels. Use label for entry at start - mList.add(new DisplayResolveInfo(ro, roLabel, null, null)); + addResolveInfo(new DisplayResolveInfo(ro, roLabel, null, null)); } else { mShowExtended = true; boolean usePkg = false; @@ -951,32 +1006,34 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic } if (usePkg) { // Use application name for all entries from start to end-1 - mList.add(new DisplayResolveInfo(add, roLabel, + addResolveInfo(new DisplayResolveInfo(add, roLabel, add.activityInfo.packageName, null)); } else { // Use package name for all entries from start to end-1 - mList.add(new DisplayResolveInfo(add, roLabel, + addResolveInfo(new DisplayResolveInfo(add, roLabel, add.activityInfo.applicationInfo.loadLabel(mPm), null)); } } } } + private void addResolveInfo(DisplayResolveInfo dri) { + if (dri.ri.targetUserId != UserHandle.USER_CURRENT && mOtherProfile == null) { + // So far we only support a single other profile at a time. + // The first one we see gets special treatment. + mOtherProfile = dri; + } else { + mList.add(dri); + } + } + public ResolveInfo resolveInfoForPosition(int position, boolean filtered) { return (filtered ? getItem(position) : mList.get(position)).ri; } public Intent intentForPosition(int position, boolean filtered) { DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position); - - Intent intent = new Intent(dri.origIntent != null ? dri.origIntent : - getReplacementIntent(dri.ri.activityInfo, mIntent)); - intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT - |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); - ActivityInfo ai = dri.ri.activityInfo; - intent.setComponent(new ComponentName( - ai.applicationInfo.packageName, ai.name)); - return intent; + return intentForDisplayResolveInfo(dri); } public int getCount() { @@ -1067,6 +1124,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic @Override protected void onPostExecute(DisplayResolveInfo info) { + if (mProfileView != null && mAdapter.getOtherProfile() == info) { + bindProfileView(); + } mAdapter.notifyDataSetChanged(); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index c00d209..0dfb11a 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -94,7 +94,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 114 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 115 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 5e610ed..40c009f 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -40,8 +40,10 @@ interface IStatusBarService // You need the STATUS_BAR_SERVICE permission void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList, out int[] switches, out List<IBinder> binders); - void onPanelRevealed(); + void onPanelRevealed(boolean clearNotificationEffects); void onPanelHidden(); + // Mark current notifications as "seen" and stop ringing, vibrating, blinking. + void clearNotificationEffects(); void onNotificationClick(String key); void onNotificationActionClick(String key, int actionIndex); void onNotificationError(String pkg, String tag, int id, diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java index 054ca30..8d1f73a 100644 --- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java +++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java @@ -97,6 +97,7 @@ public class ToolbarWidgetWrapper implements DecorToolbar { mTitle = toolbar.getTitle(); mSubtitle = toolbar.getSubtitle(); mTitleSet = mTitle != null; + mNavIcon = mToolbar.getNavigationIcon(); final TypedArray a = toolbar.getContext().obtainStyledAttributes(null, R.styleable.ActionBar, R.attr.actionBarStyle, 0); mDefaultNavigationIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator); @@ -120,7 +121,7 @@ public class ToolbarWidgetWrapper implements DecorToolbar { if (icon != null) { setIcon(icon); } - if (mDefaultNavigationIcon != null) { + if (mNavIcon == null && mDefaultNavigationIcon != null) { setNavigationIcon(mDefaultNavigationIcon); } setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0)); |
