diff options
32 files changed, 820 insertions, 306 deletions
diff --git a/api/current.txt b/api/current.txt index 27b107a..707ddab 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5441,6 +5441,7 @@ package android.app.admin { field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0 field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1 field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1 + field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2 } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index d00cbb7..0e1c85c 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1473,22 +1473,30 @@ public class DevicePolicyManager { /** * Flag for {@link #wipeData(int)}: also erase the device's external - * storage. + * storage (such as SD cards). */ public static final int WIPE_EXTERNAL_STORAGE = 0x0001; /** + * 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. + */ + public static final int WIPE_RESET_PROTECTION_DATA = 0x0002; + + /** * Ask the user data be wiped. This will cause the device to reboot, - * erasing all user data while next booting up. External storage such - * as SD cards will be also erased if the flag {@link #WIPE_EXTERNAL_STORAGE} - * is set. + * erasing all user data while next booting up. * * <p>The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call * this method; if it has not, a security exception will be thrown. * - * @param flags Bit mask of additional options: currently 0 and - * {@link #WIPE_EXTERNAL_STORAGE} are supported. + * @param flags Bit mask of additional options: currently supported flags + * are {@link #WIPE_EXTERNAL_STORAGE} and + * {@link #WIPE_RESET_PROTECTION_DATA}. */ public void wipeData(int flags) { if (mService != null) { diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml index 4b38ad3..0244891 100644 --- a/data/fonts/fallback_fonts.xml +++ b/data/fonts/fallback_fonts.xml @@ -319,6 +319,11 @@ </family> <family> <fileset> + <file>Lohit-Odia.ttf</file> + </fileset> + </family> + <family> + <fileset> <file lang="zh-Hans">NotoSansHans-Regular.otf</file> </fileset> </family> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 4493554..a62e972 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -277,6 +277,9 @@ <family> <font weight="400" style="normal">NotoSansYi-Regular.ttf</font> </family> + <family> + <font weight="400" style="normal">Lohit-Odia.ttf</font> + </family> <family lang="zh-Hans"> <font weight="400" style="normal">NotoSansHans-Regular.otf</font> </family> diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index eb0948f..bbba2dd 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -105,8 +105,11 @@ void RenderNode::setStagingDisplayList(DisplayListData* data) { * display list. This function should remain in sync with the replay() function. */ void RenderNode::output(uint32_t level) { - ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this, - getName(), isRenderable()); + ALOGD("%*sStart display list (%p, %s%s%s%s)", (level - 1) * 2, "", this, + getName(), + (properties().hasShadow() ? ", casting shadow" : ""), + (isRenderable() ? "" : ", empty"), + (mLayer != NULL ? ", on HW Layer" : "")); ALOGD("%*s%s %d", level * 2, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index b936d4b..31c4f22 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -570,7 +570,7 @@ public: } bool hasShadow() const { - return getZ() >= 0.0f + return getZ() > 0.0f && getOutline().getPath() != NULL && getOutline().getAlpha() != 0.0f; } diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 39528be..4f39ac9 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -60,6 +60,8 @@ CanvasContext::~CanvasContext() { void CanvasContext::destroy() { stopDrawing(); + setSurface(NULL); + mEglManager.usePBufferSurface(); freePrefetechedLayers(); destroyHardwareResources(); mAnimationContext->destroy(); @@ -67,7 +69,6 @@ void CanvasContext::destroy() { delete mCanvas; mCanvas = 0; } - setSurface(NULL); } void CanvasContext::setSurface(ANativeWindow* window) { diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk index 9622073..7bdce7f 100644 --- a/libs/hwui/tests/Android.mk +++ b/libs/hwui/tests/Android.mk @@ -19,6 +19,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES +LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" LOCAL_SRC_FILES:= \ diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 3f08305..0642bcd 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -470,6 +470,49 @@ public class AudioManager { public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; /** + * Adjusting the volume down from vibrated was prevented, display a hint in the UI. + * @hide + */ + public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11; + + private static final String[] FLAG_NAMES = { + "FLAG_SHOW_UI", + "FLAG_ALLOW_RINGER_MODES", + "FLAG_PLAY_SOUND", + "FLAG_REMOVE_SOUND_AND_VIBRATE", + "FLAG_VIBRATE", + "FLAG_FIXED_VOLUME", + "FLAG_BLUETOOTH_ABS_VOLUME", + "FLAG_SHOW_SILENT_HINT", + "FLAG_HDMI_SYSTEM_AUDIO_VOLUME", + "FLAG_ACTIVE_MEDIA_ONLY", + "FLAG_SHOW_UI_WARNINGS", + "FLAG_SHOW_VIBRATE_HINT", + }; + + /** @hide */ + public static String flagsToString(int flags) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < FLAG_NAMES.length; i++) { + final int flag = 1 << i; + if ((flags & flag) != 0) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(FLAG_NAMES[i]); + flags &= ~flag; + } + } + if (flags != 0) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(flags); + } + return sb.toString(); + } + + /** * Ringer mode that will be silent and will not vibrate. (This overrides the * vibrate setting.) * @@ -857,7 +900,7 @@ public class AudioManager { public int getRingerMode() { IAudioService service = getService(); try { - return service.getRingerMode(); + return service.getRingerModeExternal(); } catch (RemoteException e) { Log.e(TAG, "Dead object in getRingerMode", e); return RINGER_MODE_NORMAL; @@ -977,21 +1020,12 @@ public class AudioManager { * @see #isVolumeFixed() */ public void setRingerMode(int ringerMode) { - setRingerMode(ringerMode, true /*checkZen*/); - } - - /** - * @see #setRingerMode(int) - * @param checkZen Update zen mode if necessary to compensate. - * @hide - */ - public void setRingerMode(int ringerMode, boolean checkZen) { if (!isValidRingerMode(ringerMode)) { return; } IAudioService service = getService(); try { - service.setRingerMode(ringerMode, checkZen); + service.setRingerModeExternal(ringerMode, mContext.getOpPackageName()); } catch (RemoteException e) { Log.e(TAG, "Dead object in setRingerMode", e); } @@ -3308,6 +3342,31 @@ public class AudioManager { } /** + * Only useful for volume controllers. + * @hide + */ + public void setRingerModeInternal(int ringerMode) { + try { + getService().setRingerModeInternal(ringerMode, mContext.getOpPackageName()); + } catch (RemoteException e) { + Log.w(TAG, "Error calling setRingerModeInternal", e); + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public int getRingerModeInternal() { + try { + return getService().getRingerModeInternal(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling getRingerModeInternal", e); + return RINGER_MODE_NORMAL; + } + } + + /** * Set Hdmi Cec system audio mode. * * @param on whether to be on system audio mode diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java index a6cc493..d9586bc 100644 --- a/media/java/android/media/AudioManagerInternal.java +++ b/media/java/android/media/AudioManagerInternal.java @@ -38,4 +38,20 @@ public abstract class AudioManagerInternal { public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage, int uid); + + public abstract void setRingerModeDelegate(RingerModeDelegate delegate); + + public abstract int getRingerModeInternal(); + + public abstract void setRingerModeInternal(int ringerMode, String caller); + + public interface RingerModeDelegate { + /** Called when external ringer mode is evaluated, returns the new internal ringer mode */ + int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, + int ringerModeInternal); + + /** Called when internal ringer mode is evaluated, returns the new external ringer mode */ + int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, + int ringerModeExternal); + } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index b6b24a4..e5ae93c 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -66,7 +66,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; -import android.provider.Settings.Global; import android.provider.Settings.System; import android.telecom.TelecomManager; import android.text.TextUtils; @@ -375,7 +374,8 @@ public class AudioService extends IAudioService.Stub { * {@link AudioManager#RINGER_MODE_VIBRATE}. */ // protected by mSettingsLock - private int mRingerMode; + private int mRingerMode; // internal ringer mode, affects muting of underlying streams + private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager) /** @see System#MODE_RINGER_STREAMS_AFFECTED */ private int mRingerModeAffectedStreams = 0; @@ -532,6 +532,8 @@ public class AudioService extends IAudioService.Stub { private static Long mLastDeviceConnectMsgTime = new Long(0); + private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -546,7 +548,7 @@ public class AudioService extends IAudioService.Stub { com.android.internal.R.bool.config_voice_capable)) { mPlatformType = PLATFORM_VOICE; } else if (context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TELEVISION)) { + PackageManager.FEATURE_LEANBACK)) { mPlatformType = PLATFORM_TELEVISION; } else { mPlatformType = PLATFORM_DEFAULT; @@ -619,7 +621,7 @@ public class AudioService extends IAudioService.Stub { // Call setRingerModeInt() to apply correct mute // state on streams affected by ringer mode. mRingerModeMutedStreams = 0; - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); // Register for device connection intent broadcasts. IntentFilter intentFilter = @@ -829,7 +831,7 @@ public class AudioService extends IAudioService.Stub { if (updateVolumes) { mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]); // apply stream mute states according to new value of mRingerModeAffectedStreams - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, SENDMSG_QUEUE, @@ -883,6 +885,9 @@ public class AudioService extends IAudioService.Stub { } synchronized(mSettingsLock) { mRingerMode = ringerMode; + if (mRingerModeExternal == -1) { + mRingerModeExternal = mRingerMode; + } // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting // are still needed while setVibrateSetting() and getVibrateSetting() are being @@ -1067,7 +1072,7 @@ public class AudioService extends IAudioService.Stub { // or the stream type is one that is affected by ringer modes if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (streamTypeAlias == getMasterStreamType())) { - int ringerMode = getRingerMode(); + int ringerMode = getRingerModeInternal(); // do not vibrate if already in vibrate mode if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { flags &= ~AudioManager.FLAG_VIBRATE; @@ -1080,6 +1085,10 @@ public class AudioService extends IAudioService.Stub { if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { flags |= AudioManager.FLAG_SHOW_SILENT_HINT; } + // If suppressing a volume down adjustment in vibrate mode, display the UI hint + if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) { + flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT; + } } int oldIndex = mStreamStates[streamType].getIndex(device); @@ -1206,7 +1215,7 @@ public class AudioService extends IAudioService.Stub { } else { newRingerMode = AudioManager.RINGER_MODE_NORMAL; } - setRingerMode(newRingerMode, false /*checkZen*/); + setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/); } } @@ -1769,8 +1778,15 @@ public class AudioService extends IAudioService.Stub { : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY); } - /** @see AudioManager#getRingerMode() */ - public int getRingerMode() { + @Override + public int getRingerModeExternal() { + synchronized(mSettingsLock) { + return mRingerModeExternal; + } + } + + @Override + public int getRingerModeInternal() { synchronized(mSettingsLock) { return mRingerMode; } @@ -1787,36 +1803,57 @@ public class AudioService extends IAudioService.Stub { return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX; } - /** @see AudioManager#setRingerMode(int) */ - public void setRingerMode(int ringerMode, boolean checkZen) { + public void setRingerModeExternal(int ringerMode, String caller) { + setRingerMode(ringerMode, caller, true /*external*/); + } + + public void setRingerModeInternal(int ringerMode, String caller) { + enforceSelfOrSystemUI("setRingerModeInternal"); + setRingerMode(ringerMode, caller, false /*external*/); + } + + private void setRingerMode(int ringerMode, String caller, boolean external) { if (mUseFixedVolume || isPlatformTelevision()) { return; } + if (caller == null || caller.length() == 0) { + throw new IllegalArgumentException("Bad caller: " + caller); + } ensureValidRingerMode(ringerMode); if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { ringerMode = AudioManager.RINGER_MODE_SILENT; } - if (checkZen) { - checkZen(ringerMode); - } - if (ringerMode != getRingerMode()) { - setRingerModeInt(ringerMode, true); - // Send sticky broadcast - broadcastRingerMode(ringerMode); + final int ringerModeInternal = getRingerModeInternal(); + final int ringerModeExternal = getRingerModeExternal(); + if (external) { + setRingerModeExt(ringerMode); + if (mRingerModeDelegate != null) { + ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal, + ringerMode, caller, ringerModeInternal); + } + if (ringerMode != ringerModeInternal) { + setRingerModeInt(ringerMode, true /*persist*/); + } + } else /*internal*/ { + if (ringerMode != ringerModeInternal) { + setRingerModeInt(ringerMode, true /*persist*/); + mVolumeController.postInternalRingerModeChanged(ringerMode); + } + if (mRingerModeDelegate != null) { + ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal, + ringerMode, caller, ringerModeExternal); + } + setRingerModeExt(ringerMode); } } - private void checkZen(int ringerMode) { - // leave zen when callers set ringer-mode = normal or vibrate - final int zen = Global.getInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF); - if (ringerMode != AudioManager.RINGER_MODE_SILENT && zen != Global.ZEN_MODE_OFF) { - final long ident = Binder.clearCallingIdentity(); - try { - Global.putInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF); - } finally { - Binder.restoreCallingIdentity(ident); - } + private void setRingerModeExt(int ringerMode) { + synchronized(mSettingsLock) { + if (ringerMode == mRingerModeExternal) return; + mRingerModeExternal = ringerMode; } + // Send sticky broadcast + broadcastRingerMode(ringerMode); } private void setRingerModeInt(int ringerMode, boolean persist) { @@ -1829,34 +1866,35 @@ public class AudioService extends IAudioService.Stub { // Unmute stream if previously muted by ringer mode and ringer mode // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. int numStreamTypes = AudioSystem.getNumStreamTypes(); + final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE + || ringerMode == AudioManager.RINGER_MODE_SILENT; for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (isStreamMutedByRingerMode(streamType)) { - if (!isStreamAffectedByRingerMode(streamType) || - ringerMode == AudioManager.RINGER_MODE_NORMAL) { - // ring and notifications volume should never be 0 when not silenced - // on voice capable devices or devices that support vibration - if ((isPlatformVoice() || mHasVibrator) && - mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { - synchronized (VolumeStreamState.class) { - Set set = mStreamStates[streamType].mIndex.entrySet(); - Iterator i = set.iterator(); - while (i.hasNext()) { - Map.Entry entry = (Map.Entry)i.next(); - if ((Integer)entry.getValue() == 0) { - entry.setValue(10); - } + final boolean isMuted = isStreamMutedByRingerMode(streamType); + final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType); + if (isMuted == shouldMute) continue; + if (!shouldMute) { + // unmute + // ring and notifications volume should never be 0 when not silenced + // on voice capable devices or devices that support vibration + if ((isPlatformVoice() || mHasVibrator) && + mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { + synchronized (VolumeStreamState.class) { + Set set = mStreamStates[streamType].mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + if ((Integer)entry.getValue() == 0) { + entry.setValue(10); } } } - mStreamStates[streamType].mute(null, false); - mRingerModeMutedStreams &= ~(1 << streamType); } + mStreamStates[streamType].mute(null, false); + mRingerModeMutedStreams &= ~(1 << streamType); } else { - if (isStreamAffectedByRingerMode(streamType) && - ringerMode != AudioManager.RINGER_MODE_NORMAL) { - mStreamStates[streamType].mute(null, true); - mRingerModeMutedStreams |= (1 << streamType); - } + // mute + mStreamStates[streamType].mute(null, true); + mRingerModeMutedStreams |= (1 << streamType); } } @@ -1888,10 +1926,10 @@ public class AudioService extends IAudioService.Stub { switch (getVibrateSetting(vibrateType)) { case AudioManager.VIBRATE_SETTING_ON: - return getRingerMode() != AudioManager.RINGER_MODE_SILENT; + return getRingerModeInternal() != AudioManager.RINGER_MODE_SILENT; case AudioManager.VIBRATE_SETTING_ONLY_SILENT: - return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; + return getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE; case AudioManager.VIBRATE_SETTING_OFF: // return false, even for incoming calls @@ -2352,7 +2390,7 @@ public class AudioService extends IAudioService.Stub { // apply new ringer mode before checking volume for alias streams so that streams // muted by ringer mode have the correct volume - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); checkAllFixedVolumeDevices(); checkAllAliasStreamVolumes(); @@ -3003,7 +3041,7 @@ public class AudioService extends IAudioService.Stub { */ private int checkForRingerModeChange(int oldIndex, int direction, int step) { int result = FLAG_ADJUST_VOLUME; - int ringerMode = getRingerMode(); + int ringerMode = getRingerModeInternal(); switch (ringerMode) { case RINGER_MODE_NORMAL: @@ -3037,6 +3075,8 @@ public class AudioService extends IAudioService.Stub { if (VOLUME_SETS_RINGER_MODE_SILENT && mPrevVolDirection != AudioManager.ADJUST_LOWER) { ringerMode = RINGER_MODE_SILENT; + } else { + result |= AudioManager.FLAG_SHOW_VIBRATE_HINT; } } else if (direction == AudioManager.ADJUST_RAISE) { ringerMode = RINGER_MODE_NORMAL; @@ -3062,7 +3102,7 @@ public class AudioService extends IAudioService.Stub { break; } - setRingerMode(ringerMode, false /*checkZen*/); + setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/); mPrevVolDirection = direction; @@ -4136,7 +4176,7 @@ public class AudioService extends IAudioService.Stub { case MSG_PERSIST_RINGER_MODE: // note that the value persisted is the current ringer mode, not the // value of ringer mode as of the time the request was made to persist - persistRingerMode(getRingerMode()); + persistRingerMode(getRingerModeInternal()); break; case MSG_MEDIA_SERVER_DIED: @@ -4188,7 +4228,7 @@ public class AudioService extends IAudioService.Stub { } // Restore ringer mode - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); // Restore master volume restoreMasterVolume(); @@ -4358,7 +4398,7 @@ public class AudioService extends IAudioService.Stub { * Ensure all stream types that should be affected by ringer mode * are in the proper state. */ - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); } readDockAudioSettings(mContentResolver); } @@ -5110,7 +5150,7 @@ public class AudioService extends IAudioService.Stub { (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); } // take new state into account for streams muted by ringer mode - setRingerModeInt(getRingerMode(), false); + setRingerModeInt(getRingerModeInternal(), false); } sendMsg(mAudioHandler, @@ -5346,7 +5386,7 @@ public class AudioService extends IAudioService.Stub { private boolean mHdmiSystemAudioSupported = false; // Set only when device is tv. private HdmiTvClient mHdmiTvClient; - // true if the device has system feature PackageManager.FEATURE_TELEVISION. + // true if the device has system feature PackageManager.FEATURE_LEANBACK. // cached HdmiControlManager interface private HdmiControlManager mHdmiManager; // Set only when device is a set-top box. @@ -5451,11 +5491,13 @@ public class AudioService extends IAudioService.Stub { private void dumpRingerMode(PrintWriter pw) { pw.println("\nRinger mode: "); - pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]); + pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]); + pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]); pw.print("- ringer mode affected streams = 0x"); pw.println(Integer.toHexString(mRingerModeAffectedStreams)); pw.print("- ringer mode muted streams = 0x"); pw.println(Integer.toHexString(mRingerModeMutedStreams)); + pw.print("- delegate = "); pw.println(mRingerModeDelegate); } @Override @@ -5477,6 +5519,7 @@ public class AudioService extends IAudioService.Stub { pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand); pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs); pw.print(" mMcc="); pw.println(mMcc); + pw.print(" mHasVibrator="); pw.println(mHasVibrator); } private static String safeMediaVolumeStateToString(Integer state) { @@ -5668,6 +5711,16 @@ public class AudioService extends IAudioService.Stub { Log.w(TAG, "Error calling dismiss", e); } } + + public void postInternalRingerModeChanged(int mode) { + if (mController == null) + return; + try { + mController.internalRingerModeChanged(mode); + } catch (RemoteException e) { + Log.w(TAG, "Error calling internalRingerModeChanged", e); + } + } } /** @@ -5675,6 +5728,13 @@ public class AudioService extends IAudioService.Stub { * LocalServices. */ final class AudioServiceInternal extends AudioManagerInternal { + @Override + public void setRingerModeDelegate(RingerModeDelegate delegate) { + mRingerModeDelegate = delegate; + if (mRingerModeDelegate != null) { + setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate"); + } + } @Override public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags, @@ -5701,6 +5761,16 @@ public class AudioService extends IAudioService.Stub { int uid) { adjustMasterVolume(steps, flags, callingPackage, uid); } + + @Override + public int getRingerModeInternal() { + return AudioService.this.getRingerModeInternal(); + } + + @Override + public void setRingerModeInternal(int ringerMode, String caller) { + AudioService.this.setRingerModeInternal(ringerMode, caller); + } } //========================================================================================== diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index b691447..4d8aa76 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -77,9 +77,13 @@ interface IAudioService { void setMicrophoneMute(boolean on, String callingPackage); - void setRingerMode(int ringerMode, boolean checkZen); + void setRingerModeExternal(int ringerMode, String caller); - int getRingerMode(); + void setRingerModeInternal(int ringerMode, String caller); + + int getRingerModeExternal(); + + int getRingerModeInternal(); boolean isValidRingerMode(int ringerMode); diff --git a/media/java/android/media/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl index e3593a6..c31d80c 100644 --- a/media/java/android/media/IVolumeController.aidl +++ b/media/java/android/media/IVolumeController.aidl @@ -34,4 +34,6 @@ oneway interface IVolumeController { void setLayoutDirection(int layoutDirection); void dismiss(); + + void internalRingerModeChanged(int mode); } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index bdd62f2..8985b52 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -1784,11 +1784,11 @@ final public class MediaCodec { mYOffset = yOffset; mInfo = info; - // read media-info. the size of media info can be 80 or 156 depending on + // read media-info. the size of media info can be 80 or 156/160 depending on // whether it was created on a 32- or 64-bit process. See MediaImage - if (info.remaining() == 80 || info.remaining() == 156) { - boolean sizeIsLong = info.remaining() == 156; - int type = info.getInt(); + if (info.remaining() == 80 || info.remaining() == 156 || info.remaining() == 160) { + boolean sizeIsLong = info.remaining() != 80; + int type = readInt(info, info.remaining() == 160); if (type != TYPE_YUV) { throw new UnsupportedOperationException("unsupported type: " + type); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 9246f4d..54eb18c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -53,6 +53,7 @@ import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; @@ -267,6 +268,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private UnlockMethodCache mUnlockMethodCache; private DozeServiceHost mDozeServiceHost; private boolean mScreenOnComingFromTouch; + private PointF mScreenOnTouchLocation; int mPixelFormat; Object mQueueLock = new Object(); @@ -1028,6 +1030,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } + public void onInternalRingerModeChanged() { + if (mIconPolicy != null) { + mIconPolicy.updateVolumeZen(); + } + } + private void startKeyguard() { KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, @@ -3705,7 +3713,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } boolean animate = !mDozing && mDozeScrimController.isPulsing(); mNotificationPanel.setDozing(mDozing, animate); - mStackScroller.setDark(mDozing, animate); + mStackScroller.setDark(mDozing, animate, mScreenOnTouchLocation); mScrimController.setDozing(mDozing); mDozeScrimController.setDozing(mDozing, animate); } @@ -3961,6 +3969,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void onScreenTurnedOff() { mScreenOnFromKeyguard = false; mScreenOnComingFromTouch = false; + mScreenOnTouchLocation = null; mStackScroller.setAnimationsEnabled(false); updateVisibleToUser(); } @@ -4083,14 +4092,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return !mNotificationData.getActiveNotifications().isEmpty(); } - public void wakeUpIfDozing(long time, boolean fromTouch) { + public void wakeUpIfDozing(long time, MotionEvent event) { if (mDozing && mDozeScrimController.isPulsing()) { PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); pm.wakeUp(time); - if (fromTouch) { - mScreenOnComingFromTouch = true; - mNotificationPanel.setTouchDisabled(false); - } + mScreenOnComingFromTouch = true; + mScreenOnTouchLocation = new PointF(event.getX(), event.getY()); + mNotificationPanel.setTouchDisabled(false); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 60d23ce..94401d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -208,7 +208,7 @@ public class PhoneStatusBarPolicy { } } - private final void updateVolumeZen() { + public final void updateVolumeZen() { AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); boolean zenVisible = false; @@ -230,7 +230,7 @@ public class PhoneStatusBarPolicy { } if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS && - audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { + audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) { volumeVisible = true; volumeIconId = R.drawable.stat_sys_ringer_vibrate; volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 47ec08d..a96f4e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -173,7 +173,7 @@ public class StatusBarWindowView extends FrameLayout { intercept = mDragDownHelper.onInterceptTouchEvent(ev); // wake up on a touch down event, if dozing if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { - mService.wakeUpIfDozing(ev.getEventTime(), true); + mService.wakeUpIfDozing(ev.getEventTime(), ev); } } if (!intercept) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 415eb27..37ed7d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -157,8 +157,9 @@ public class ZenModeControllerImpl implements ZenModeController { if (mRegistered) { mContext.unregisterReceiver(mReceiver); } - mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), - new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED), null, null); + final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); + filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); + mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null); mRegistered = true; mSetupObserver.register(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java index 3d4cda6..753a7f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java @@ -34,6 +34,7 @@ public class AnimationFilter { boolean hasDelays; boolean hasGoToFullShadeEvent; boolean hasDarkEvent; + int darkAnimationOriginIndex; public AnimationFilter animateAlpha() { animateAlpha = true; @@ -94,14 +95,16 @@ public class AnimationFilter { reset(); int size = events.size(); for (int i = 0; i < size; i++) { + NotificationStackScrollLayout.AnimationEvent ev = events.get(i); combineFilter(events.get(i).filter); - if (events.get(i).animationType == + if (ev.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_GO_TO_FULL_SHADE) { hasGoToFullShadeEvent = true; } - if (events.get(i).animationType == + if (ev.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_DARK) { hasDarkEvent = true; + darkAnimationOriginIndex = ev.darkAnimationOriginIndex; } } } @@ -132,5 +135,7 @@ public class AnimationFilter { hasDelays = false; hasGoToFullShadeEvent = false; hasDarkEvent = false; + darkAnimationOriginIndex = + NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 16ff3dc..2a393bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -16,10 +16,12 @@ package com.android.systemui.statusbar.stack; +import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PointF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -149,6 +151,7 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mDimmedNeedsAnimation; private boolean mHideSensitiveNeedsAnimation; private boolean mDarkNeedsAnimation; + private int mDarkAnimationOriginIndex; private boolean mActivateNeedsAnimation; private boolean mGoToFullShadeNeedsAnimation; private boolean mIsExpanded = true; @@ -210,6 +213,7 @@ public class NotificationStackScrollLayout extends ViewGroup } }; private PhoneStatusBar mPhoneStatusBar; + private int[] mTempInt2 = new int[2]; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -587,10 +591,38 @@ public class NotificationStackScrollLayout extends ViewGroup return getChildAtPosition(ev.getX(), ev.getY()); } + public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) { + getLocationOnScreen(mTempInt2); + float localTouchY = touchY - mTempInt2[1]; + + ExpandableView closestChild = null; + float minDist = Float.MAX_VALUE; + + // find the view closest to the location, accounting for GONE views + final int count = getChildCount(); + for (int childIdx = 0; childIdx < count; childIdx++) { + ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx); + if (slidingChild.getVisibility() == GONE + || slidingChild instanceof StackScrollerDecorView + || slidingChild == mSpeedBumpView) { + continue; + } + float childTop = slidingChild.getTranslationY(); + float top = childTop + slidingChild.getClipTopAmount(); + float bottom = childTop + slidingChild.getActualHeight(); + + float dist = Math.min(Math.abs(top - localTouchY), Math.abs(bottom - localTouchY)); + if (dist < minDist) { + closestChild = slidingChild; + minDist = dist; + } + } + return closestChild; + } + public ExpandableView getChildAtRawPosition(float touchX, float touchY) { - int[] location = new int[2]; - getLocationOnScreen(location); - return getChildAtPosition(touchX - location[0], touchY - location[1]); + getLocationOnScreen(mTempInt2); + return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]); } public ExpandableView getChildAtPosition(float touchX, float touchY) { @@ -1818,8 +1850,9 @@ public class NotificationStackScrollLayout extends ViewGroup private void generateDarkEvent() { if (mDarkNeedsAnimation) { - mAnimationEvents.add( - new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DARK)); + AnimationEvent ev = new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DARK); + ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; + mAnimationEvents.add(ev); } mDarkNeedsAnimation = false; } @@ -2151,7 +2184,7 @@ public class NotificationStackScrollLayout extends ViewGroup mEmptyShadeView.setInvisible(); mGoToFullShadeNeedsAnimation = true; mGoToFullShadeDelay = delay; - mNeedsAnimation = true; + mNeedsAnimation = true; requestChildrenUpdate(); } @@ -2182,15 +2215,46 @@ public class NotificationStackScrollLayout extends ViewGroup /** * See {@link AmbientState#setDark}. */ - public void setDark(boolean dark, boolean animate) { + public void setDark(boolean dark, boolean animate, @Nullable PointF touchWakeUpScreenLocation) { mAmbientState.setDark(dark); if (animate && mAnimationsEnabled) { mDarkNeedsAnimation = true; + mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); mNeedsAnimation = true; } requestChildrenUpdate(); } + private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { + if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) { + return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE; + } + if (screenLocation.y > getBottomMostNotificationBottom()) { + return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW; + } + View child = getClosestChildAtRawPosition(screenLocation.x, screenLocation.y); + if (child != null) { + return getNotGoneIndex(child); + } else { + return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE; + } + } + + private int getNotGoneIndex(View child) { + int count = getChildCount(); + int notGoneIndex = 0; + for (int i = 0; i < count; i++) { + View v = getChildAt(i); + if (child == v) { + return notGoneIndex; + } + if (v.getVisibility() != View.GONE) { + notGoneIndex++; + } + } + return -1; + } + public void setDismissView(DismissView dismissView) { mDismissView = dismissView; addView(mDismissView); @@ -2556,12 +2620,16 @@ public class NotificationStackScrollLayout extends ViewGroup static final int ANIMATION_TYPE_VIEW_RESIZE = 12; static final int ANIMATION_TYPE_EVERYTHING = 13; + static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1; + static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2; + final long eventStartTime; final View changingView; final int animationType; final AnimationFilter filter; final long length; View viewAfterChangingView; + int darkAnimationOriginIndex; AnimationEvent(View view, int type) { this(view, type, LENGTHS[type]); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index 05077bf..b027787 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -315,7 +315,17 @@ public class StackStateAnimator { } private long calculateDelayDark(StackScrollState.ViewState viewState) { - return viewState.notGoneIndex * ANIMATION_DELAY_PER_ELEMENT_DARK; + int referenceIndex; + if (mAnimationFilter.darkAnimationOriginIndex == + NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) { + referenceIndex = 0; + } else if (mAnimationFilter.darkAnimationOriginIndex == + NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW) { + referenceIndex = mHostLayout.getNotGoneChildCount() - 1; + } else { + referenceIndex = mAnimationFilter.darkAnimationOriginIndex; + } + return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK; } private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java b/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java new file mode 100644 index 0000000..9438af1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.view.View; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; + +public class IconPulser { + private static final float PULSE_SCALE = 1.1f; + + private final Interpolator mFastOutSlowInInterpolator; + + public IconPulser(Context context) { + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + android.R.interpolator.fast_out_slow_in); + } + + public void start(final View target) { + if (target == null || target.getScaleX() != 1) return; // n/a, or already running + target.animate().cancel(); + target.animate().scaleX(PULSE_SCALE).scaleY(PULSE_SCALE) + .setInterpolator(mFastOutSlowInInterpolator) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + target.animate().scaleX(1).scaleY(1).setListener(null); + } + }); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java index 351911c..1fe4698 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java @@ -124,6 +124,8 @@ public class VolumePanel extends Handler implements DemoMode { private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13; private static final int MSG_USER_ACTIVITY = 14; private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15; + private static final int MSG_ZEN_MODE_CHANGED = 16; + private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 17; // Pseudo stream type for master volume private static final int STREAM_MASTER = -100; @@ -169,6 +171,8 @@ public class VolumePanel extends Handler implements DemoMode { private final ViewGroup mSliderPanel; /** The zen mode configuration panel view */ private ZenModePanel mZenPanel; + /** The component currently suppressing notification stream effects */ + private ComponentName mNotificationEffectsSuppressor; private Callback mCallback; @@ -178,6 +182,7 @@ public class VolumePanel extends Handler implements DemoMode { private SparseArray<StreamControl> mStreamControls; private final AccessibilityManager mAccessibilityManager; private final SecondaryIconTransition mSecondaryIconTransition; + private final IconPulser mIconPulser; private enum StreamResources { BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO, @@ -188,7 +193,7 @@ public class VolumePanel extends Handler implements DemoMode { RingerStream(AudioManager.STREAM_RING, R.string.volume_icon_description_ringer, com.android.systemui.R.drawable.ic_ringer_audible, - com.android.systemui.R.drawable.ic_ringer_vibrate, + com.android.systemui.R.drawable.ic_ringer_mute, false), VoiceStream(AudioManager.STREAM_VOICE_CALL, R.string.volume_icon_description_incall, @@ -208,7 +213,7 @@ public class VolumePanel extends Handler implements DemoMode { NotificationStream(AudioManager.STREAM_NOTIFICATION, R.string.volume_icon_description_notification, com.android.systemui.R.drawable.ic_ringer_audible, - com.android.systemui.R.drawable.ic_ringer_vibrate, + com.android.systemui.R.drawable.ic_ringer_mute, true), // for now, use media resources for master volume MasterStream(STREAM_MASTER, @@ -268,6 +273,7 @@ public class VolumePanel extends Handler implements DemoMode { // Synchronize when accessing this private ToneGenerator mToneGenerators[]; private Vibrator mVibrator; + private boolean mHasVibrator; private static AlertDialog sSafetyWarning; private static Object sSafetyWarningLock = new Object(); @@ -354,6 +360,7 @@ public class VolumePanel extends Handler implements DemoMode { mAccessibilityManager = (AccessibilityManager) context.getSystemService( Context.ACCESSIBILITY_SERVICE); mSecondaryIconTransition = new SecondaryIconTransition(); + mIconPulser = new IconPulser(context); // For now, only show master volume if master volume is supported final Resources res = context.getResources(); @@ -435,10 +442,12 @@ public class VolumePanel extends Handler implements DemoMode { mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + mHasVibrator = mVibrator != null && mVibrator.hasVibrator(); mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable); if (mZenController != null && !useMasterVolume) { mZenModeAvailable = mZenController.isZenAvailable(); + mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor(); mZenController.addCallback(mZenCallback); } @@ -470,8 +479,10 @@ public class VolumePanel extends Handler implements DemoMode { pw.print(" mTag="); pw.println(mTag); pw.print(" mRingIsSilent="); pw.println(mRingIsSilent); pw.print(" mVoiceCapable="); pw.println(mVoiceCapable); + pw.print(" mHasVibrator="); pw.println(mHasVibrator); pw.print(" mZenModeAvailable="); pw.println(mZenModeAvailable); pw.print(" mZenPanelExpanded="); pw.println(mZenPanelExpanded); + pw.print(" mNotificationEffectsSuppressor="); pw.println(mNotificationEffectsSuppressor); pw.print(" mTimeoutDelay="); pw.println(mTimeoutDelay); pw.print(" mDisabledAlpha="); pw.println(mDisabledAlpha); pw.print(" mLastRingerMode="); pw.println(mLastRingerMode); @@ -639,16 +650,19 @@ public class VolumePanel extends Handler implements DemoMode { sc.iconRes = streamRes.iconRes; sc.iconMuteRes = streamRes.iconMuteRes; sc.icon.setImageResource(sc.iconRes); - sc.icon.setClickable(isNotification); + sc.icon.setClickable(isNotification && mHasVibrator); if (isNotification) { - sc.icon.setSoundEffectsEnabled(false); - sc.icon.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - resetTimeout(); - toggle(sc); - } - }); + if (mHasVibrator) { + sc.icon.setSoundEffectsEnabled(false); + sc.iconMuteRes = com.android.systemui.R.drawable.ic_ringer_vibrate; + sc.icon.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + resetTimeout(); + toggleRinger(sc); + } + }); + } sc.iconSuppressedRes = com.android.systemui.R.drawable.ic_ringer_mute; } sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar); @@ -681,12 +695,13 @@ public class VolumePanel extends Handler implements DemoMode { } } - private void toggle(StreamControl sc) { - if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE); + private void toggleRinger(StreamControl sc) { + if (!mHasVibrator) return; + if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL) { + mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE); postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL); postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND); } } @@ -710,7 +725,7 @@ public class VolumePanel extends Handler implements DemoMode { private void updateSliderProgress(StreamControl sc, int progress) { final boolean isRinger = isNotificationOrRing(sc.streamType); - if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + if (isRinger && mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) { progress = mLastRingerProgress; } if (progress < 0) { @@ -723,21 +738,30 @@ public class VolumePanel extends Handler implements DemoMode { } private void updateSliderIcon(StreamControl sc, boolean muted) { + ComponentName suppressor = null; if (isNotificationOrRing(sc.streamType)) { - int ringerMode = mAudioManager.getRingerMode(); + suppressor = mNotificationEffectsSuppressor; + int ringerMode = mAudioManager.getRingerModeInternal(); if (ringerMode == AudioManager.RINGER_MODE_SILENT) { ringerMode = mLastRingerMode; } else { mLastRingerMode = ringerMode; } - muted = ringerMode == AudioManager.RINGER_MODE_VIBRATE; + if (mHasVibrator) { + muted = ringerMode == AudioManager.RINGER_MODE_VIBRATE; + } else { + muted = false; + } } - sc.icon.setImageResource(mDemoIcon != 0 ? mDemoIcon : muted ? sc.iconMuteRes : sc.iconRes); + sc.icon.setImageResource(mDemoIcon != 0 ? mDemoIcon + : suppressor != null ? sc.iconSuppressedRes + : muted ? sc.iconMuteRes + : sc.iconRes); } - private void updateSliderSupressor(StreamControl sc) { + private void updateSliderSuppressor(StreamControl sc) { final ComponentName suppressor = isNotificationOrRing(sc.streamType) - ? mZenController.getEffectsSuppressor() : null; + ? mNotificationEffectsSuppressor : null; if (suppressor == null) { sc.seekbarView.setVisibility(View.VISIBLE); sc.suppressorView.setVisibility(View.GONE); @@ -746,7 +770,6 @@ public class VolumePanel extends Handler implements DemoMode { sc.suppressorView.setVisibility(View.VISIBLE); sc.suppressorView.setText(mContext.getString(R.string.muted_by, getSuppressorCaption(suppressor))); - sc.icon.setImageResource(sc.iconSuppressedRes); } } @@ -777,7 +800,7 @@ public class VolumePanel extends Handler implements DemoMode { sc.icon.setImageDrawable(null); updateSliderIcon(sc, muted); updateSliderEnabled(sc, muted, false); - updateSliderSupressor(sc); + updateSliderSuppressor(sc); } private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) { @@ -787,7 +810,12 @@ public class VolumePanel extends Handler implements DemoMode { // never disable touch interactions for remote playback, the muting is not tied to // the state of the phone. sc.seekbarView.setEnabled(!fixedVolume); - } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + } else if (isRinger && mNotificationEffectsSuppressor != null) { + sc.icon.setEnabled(true); + sc.icon.setAlpha(1f); + sc.icon.setClickable(false); + } else if (isRinger + && mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) { sc.seekbarView.setEnabled(false); sc.icon.setEnabled(false); sc.icon.setAlpha(mDisabledAlpha); @@ -805,7 +833,7 @@ public class VolumePanel extends Handler implements DemoMode { if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) { if (sc.seekbarView.isEnabled()) { sc.group.setOnTouchListener(null); - sc.icon.setClickable(true); + sc.icon.setClickable(mHasVibrator); } else { final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() { @Override @@ -826,6 +854,16 @@ public class VolumePanel extends Handler implements DemoMode { } } + private void showVibrateHint() { + final StreamControl active = mStreamControls.get(mActiveStreamType); + if (active != null) { + mIconPulser.start(active.icon); + if (!hasMessages(MSG_VIBRATE)) { + sendEmptyMessageDelayed(MSG_VIBRATE, VIBRATE_DELAY); + } + } + } + private static boolean isNotificationOrRing(int streamType) { return streamType == AudioManager.STREAM_RING || streamType == AudioManager.STREAM_NOTIFICATION; @@ -953,6 +991,19 @@ public class VolumePanel extends Handler implements DemoMode { obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection, 0).sendToTarget(); } + public void postInternalRingerModeChanged(int mode) { + removeMessages(MSG_INTERNAL_RINGER_MODE_CHANGED); + obtainMessage(MSG_INTERNAL_RINGER_MODE_CHANGED, mode, 0).sendToTarget(); + } + + private static String flagsToString(int flags) { + return flags == 0 ? "0" : (flags + "=" + AudioManager.flagsToString(flags)); + } + + private static String streamToString(int stream) { + return AudioService.streamToString(stream); + } + /** * Override this if you have other work to do when the volume changes (for * example, vibrating, playing a sound, etc.). Make sure to call through to @@ -960,7 +1011,8 @@ public class VolumePanel extends Handler implements DemoMode { */ protected void onVolumeChanged(int streamType, int flags) { - if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")"); + if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamToString(streamType) + + ", flags: " + flagsToString(flags) + ")"); if ((flags & AudioManager.FLAG_SHOW_UI) != 0) { synchronized (this) { @@ -989,7 +1041,8 @@ public class VolumePanel extends Handler implements DemoMode { protected void onMuteChanged(int streamType, int flags) { - if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")"); + if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamToString(streamType) + + ", flags: " + flagsToString(flags) + ")"); StreamControl sc = mStreamControls.get(streamType); if (sc != null) { @@ -1005,8 +1058,8 @@ public class VolumePanel extends Handler implements DemoMode { mRingIsSilent = false; if (LOGD) { - Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType - + ", flags: " + flags + "), index: " + index); + Log.d(mTag, "onShowVolumeChanged(streamType: " + streamToString(streamType) + + ", flags: " + flagsToString(flags) + "), index: " + index); } // get max volume for progress bar @@ -1017,7 +1070,6 @@ public class VolumePanel extends Handler implements DemoMode { switch (streamType) { case AudioManager.STREAM_RING: { -// setRingerIcon(); Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri( mContext, RingtoneManager.TYPE_RINGTONE); if (ringuri == null) { @@ -1110,13 +1162,16 @@ public class VolumePanel extends Handler implements DemoMode { sc.seekbarView.setMax(max); } updateSliderProgress(sc, index); - updateSliderEnabled(sc, isMuted(streamType), - (flags & AudioManager.FLAG_FIXED_VOLUME) != 0); - // check for secondary-icon transition completion - if (isNotificationOrRing(streamType) && mSecondaryIconTransition.isRunning()) { - mSecondaryIconTransition.cancel(); // safe to reset - sc.seekbarView.setAlpha(0); sc.seekbarView.animate().alpha(1); - mZenPanel.setAlpha(0); mZenPanel.animate().alpha(1); + final boolean muted = isMuted(streamType); + updateSliderEnabled(sc, muted, (flags & AudioManager.FLAG_FIXED_VOLUME) != 0); + if (isNotificationOrRing(streamType)) { + // check for secondary-icon transition completion + if (mSecondaryIconTransition.isRunning()) { + mSecondaryIconTransition.cancel(); // safe to reset + sc.seekbarView.setAlpha(0); sc.seekbarView.animate().alpha(1); + mZenPanel.setAlpha(0); mZenPanel.animate().alpha(1); + } + updateSliderIcon(sc, muted); } } @@ -1134,15 +1189,20 @@ public class VolumePanel extends Handler implements DemoMode { // Do a little vibrate if applicable (only when going into vibrate mode) if ((streamType != STREAM_REMOTE_MUSIC) && ((flags & AudioManager.FLAG_VIBRATE) != 0) && - mAudioManager.isStreamAffectedByRingerMode(streamType) && - mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { + isNotificationOrRing(streamType) && + mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) { sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY); } - // Pulse the slider icon if an adjustment was suppressed due to silent mode. + // Pulse the zen icon if an adjustment was suppressed due to silent mode. if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { showSilentHint(); } + + // Pulse the slider icon & vibrate if an adjustment down was suppressed due to vibrate mode. + if ((flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) { + showVibrateHint(); + } } private void announceDialogShown() { @@ -1186,16 +1246,17 @@ public class VolumePanel extends Handler implements DemoMode { protected void onVibrate() { // Make sure we ended up in vibrate ringer mode - if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) { + if (mAudioManager.getRingerModeInternal() != AudioManager.RINGER_MODE_VIBRATE) { return; } - - mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES); + if (mVibrator != null) { + mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES); + } } protected void onRemoteVolumeChanged(MediaController controller, int flags) { - if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(controller:" + controller + ", flags: " + flags - + ")"); + if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(controller:" + controller + ", flags: " + + flagsToString(flags) + ")"); if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) { synchronized (this) { @@ -1385,7 +1446,9 @@ public class VolumePanel extends Handler implements DemoMode { break; } + case MSG_ZEN_MODE_CHANGED: case MSG_RINGER_MODE_CHANGED: + case MSG_INTERNAL_RINGER_MODE_CHANGED: case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: { if (isShowing()) { updateStates(); @@ -1491,10 +1554,15 @@ public class VolumePanel extends Handler implements DemoMode { public void onZenAvailableChanged(boolean available) { obtainMessage(MSG_ZEN_MODE_AVAILABLE_CHANGED, available ? 1 : 0, 0).sendToTarget(); } + @Override public void onEffectsSupressorChanged() { - obtainMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED, - mZenController.getEffectsSuppressor()).sendToTarget(); + mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor(); + sendEmptyMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED); + } + + public void onZenChanged(int zen) { + sendEmptyMessage(MSG_ZEN_MODE_CHANGED); } }; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java index 7102c2a..e452b22 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -182,6 +182,15 @@ public class VolumeUI extends SystemUI { } @Override + public void internalRingerModeChanged(int mode) throws RemoteException { + mPanel.postInternalRingerModeChanged(mode); + final PhoneStatusBar psb = getComponent(PhoneStatusBar.class); + if (psb != null) { + psb.onInternalRingerModeChanged(); + } + } + + @Override public ZenModeController getZenController() { return mPanel.getZenController(); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 5b37f78..b84b138 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -16,8 +16,6 @@ package com.android.systemui.volume; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -38,8 +36,6 @@ import android.util.Log; import android.util.MathUtils; import android.view.LayoutInflater; import android.view.View; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; @@ -69,7 +65,6 @@ public class ZenModePanel extends LinearLayout { private static final int FOREVER_CONDITION_INDEX = 0; private static final int TIME_CONDITION_INDEX = 1; private static final int FIRST_CONDITION_INDEX = 2; - private static final float SILENT_HINT_PULSE_SCALE = 1.1f; private static final long SELECT_DEFAULT_DELAY = 300; public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); @@ -78,7 +73,7 @@ public class ZenModePanel extends LinearLayout { private final LayoutInflater mInflater; private final H mHandler = new H(); private final Prefs mPrefs; - private final Interpolator mFastOutSlowInInterpolator; + private final IconPulser mIconPulser; private final int mSubheadWarningColor; private final int mSubheadColor; @@ -110,8 +105,7 @@ public class ZenModePanel extends LinearLayout { mContext = context; mPrefs = new Prefs(); mInflater = LayoutInflater.from(mContext.getApplicationContext()); - mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext, - android.R.interpolator.fast_out_slow_in); + mIconPulser = new IconPulser(mContext); final Resources res = mContext.getResources(); mSubheadWarningColor = res.getColor(R.color.system_warning_color); mSubheadColor = res.getColor(R.color.qs_subhead); @@ -283,16 +277,7 @@ public class ZenModePanel extends LinearLayout { if (DEBUG) Log.d(mTag, "showSilentHint"); if (mZenButtons == null || mZenButtons.getChildCount() == 0) return; final View noneButton = mZenButtons.getChildAt(0); - if (noneButton.getScaleX() != 1) return; // already running - noneButton.animate().cancel(); - noneButton.animate().scaleX(SILENT_HINT_PULSE_SCALE).scaleY(SILENT_HINT_PULSE_SCALE) - .setInterpolator(mFastOutSlowInInterpolator) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - noneButton.animate().scaleX(1).scaleY(1).setListener(null); - } - }); + mIconPulser.start(noneButton); } private void handleUpdateZen(int zen) { diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java index c960c07..9c0f987 100644 --- a/services/core/java/com/android/server/location/GpsLocationProvider.java +++ b/services/core/java/com/android/server/location/GpsLocationProvider.java @@ -788,8 +788,9 @@ public class GpsLocationProvider implements LocationProviderInterface { } if (info != null) { - boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MOBILE_DATA, 1) == 1; + boolean dataEnabled = TelephonyManager.getIntWithSubId(mContext.getContentResolver(), + Settings.Global.MOBILE_DATA, SubscriptionManager.getDefaultSubId(), + 1) == 1; boolean networkAvailable = info.isAvailable() && dataEnabled; String defaultApn = getSelectedApn(); if (defaultApn == null) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d60c57f..70d0e6a 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -847,7 +847,7 @@ public class NotificationManagerService extends SystemService { mRankingHelper = new RankingHelper(getContext(), new RankingWorkerHandler(mRankingThread.getLooper()), extractorNames); - mZenModeHelper = new ZenModeHelper(getContext(), mHandler); + mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper()); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { @Override public void onConfigChanged() { @@ -970,7 +970,7 @@ public class NotificationManagerService extends SystemService { // Grab our optional AudioService mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - mZenModeHelper.setAudioManager(mAudioManager); + mZenModeHelper.onSystemReady(); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to // bind to listener services. @@ -1412,8 +1412,8 @@ public class NotificationManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationList) { - mListeners.checkServiceTokenLocked(token); - mZenModeHelper.requestFromListener(interruptionFilter); + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + mZenModeHelper.requestFromListener(info.component, interruptionFilter); updateInterruptionFilterLocked(); } } finally { @@ -1965,7 +1965,7 @@ public class NotificationManagerService extends SystemService { final boolean convertSoundToVibration = !hasCustomVibrate && hasValidSound - && (mAudioManager.getRingerMode() + && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE); // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. @@ -1973,7 +1973,7 @@ public class NotificationManagerService extends SystemService { (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) - && !(mAudioManager.getRingerMode() + && !(mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT)) { mVibrateNotification = record; diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index 1a3da79..6960159 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -46,15 +46,15 @@ public class ZenLog { private static final int TYPE_INTERCEPTED = 1; private static final int TYPE_ALLOW_DISABLE = 2; - private static final int TYPE_SET_RINGER_MODE = 3; - private static final int TYPE_DOWNTIME = 4; - private static final int TYPE_SET_ZEN_MODE = 5; - private static final int TYPE_UPDATE_ZEN_MODE = 6; - private static final int TYPE_EXIT_CONDITION = 7; - private static final int TYPE_SUBSCRIBE = 8; - private static final int TYPE_UNSUBSCRIBE = 9; - private static final int TYPE_CONFIG = 10; - private static final int TYPE_FOLLOW_RINGER_MODE = 11; + private static final int TYPE_SET_RINGER_MODE_EXTERNAL = 3; + private static final int TYPE_SET_RINGER_MODE_INTERNAL = 4; + private static final int TYPE_DOWNTIME = 5; + private static final int TYPE_SET_ZEN_MODE = 6; + private static final int TYPE_UPDATE_ZEN_MODE = 7; + private static final int TYPE_EXIT_CONDITION = 8; + private static final int TYPE_SUBSCRIBE = 9; + private static final int TYPE_UNSUBSCRIBE = 10; + private static final int TYPE_CONFIG = 11; private static final int TYPE_NOT_INTERCEPTED = 12; private static final int TYPE_DISABLE_EFFECTS = 13; @@ -71,8 +71,22 @@ public class ZenLog { append(TYPE_NOT_INTERCEPTED, record.getKey() + "," + reason); } - public static void traceSetRingerMode(int ringerMode) { - append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode)); + public static void traceSetRingerModeExternal(int ringerModeOld, int ringerModeNew, + String caller, int ringerModeInternalIn, int ringerModeInternalOut) { + append(TYPE_SET_RINGER_MODE_EXTERNAL, caller + ",e:" + + ringerModeToString(ringerModeOld) + "->" + + ringerModeToString(ringerModeNew) + ",i:" + + ringerModeToString(ringerModeInternalIn) + "->" + + ringerModeToString(ringerModeInternalOut)); + } + + public static void traceSetRingerModeInternal(int ringerModeOld, int ringerModeNew, + String caller, int ringerModeExternalIn, int ringerModeExternalOut) { + append(TYPE_SET_RINGER_MODE_INTERNAL, caller + ",i:" + + ringerModeToString(ringerModeOld) + "->" + + ringerModeToString(ringerModeNew) + ",e:" + + ringerModeToString(ringerModeExternalIn) + "->" + + ringerModeToString(ringerModeExternalOut)); } public static void traceDowntime(int downtimeMode, int day, ArraySet<Integer> days) { @@ -103,11 +117,6 @@ public class ZenLog { append(TYPE_CONFIG, newConfig != null ? newConfig.toString() : null); } - public static void traceFollowRingerMode(int ringerMode, int oldZen, int newZen) { - append(TYPE_FOLLOW_RINGER_MODE, ringerModeToString(ringerMode) + ", " - + zenModeToString(oldZen) + " -> " + zenModeToString(newZen)); - } - public static void traceDisableEffects(NotificationRecord record, String reason) { append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason); } @@ -120,7 +129,8 @@ public class ZenLog { switch (type) { case TYPE_INTERCEPTED: return "intercepted"; case TYPE_ALLOW_DISABLE: return "allow_disable"; - case TYPE_SET_RINGER_MODE: return "set_ringer_mode"; + case TYPE_SET_RINGER_MODE_EXTERNAL: return "set_ringer_mode_external"; + case TYPE_SET_RINGER_MODE_INTERNAL: return "set_ringer_mode_internal"; case TYPE_DOWNTIME: return "downtime"; case TYPE_SET_ZEN_MODE: return "set_zen_mode"; case TYPE_UPDATE_ZEN_MODE: return "update_zen_mode"; @@ -128,7 +138,6 @@ public class ZenLog { case TYPE_SUBSCRIBE: return "subscribe"; case TYPE_UNSUBSCRIBE: return "unsubscribe"; case TYPE_CONFIG: return "config"; - case TYPE_FOLLOW_RINGER_MODE: return "follow_ringer_mode"; case TYPE_NOT_INTERCEPTED: return "not_intercepted"; case TYPE_DISABLE_EFFECTS: return "disable_effects"; default: return "unknown"; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 992b6aa..5ceb503 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -21,20 +21,20 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import android.app.AppOpsManager; import android.app.Notification; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; import android.media.AudioAttributes; import android.media.AudioManager; +import android.media.AudioManagerInternal; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.UserHandle; import android.provider.Settings.Global; import android.provider.Settings.Secure; @@ -45,6 +45,7 @@ import android.util.Log; import android.util.Slog; import com.android.internal.R; +import com.android.server.LocalServices; import libcore.io.IoUtils; @@ -60,12 +61,12 @@ import java.util.Objects; /** * NotificationManagerService helper for functionality related to zen mode. */ -public class ZenModeHelper { +public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate { private static final String TAG = "ZenModeHelper"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Context mContext; - private final Handler mHandler; + private final H mHandler; private final SettingsObserver mSettingsObserver; private final AppOpsManager mAppOps; private final ZenModeConfig mDefaultConfig; @@ -74,21 +75,17 @@ public class ZenModeHelper { private ComponentName mDefaultPhoneApp; private int mZenMode; private ZenModeConfig mConfig; - private AudioManager mAudioManager; + private AudioManagerInternal mAudioManager; private int mPreviousRingerMode = -1; - public ZenModeHelper(Context context, Handler handler) { + public ZenModeHelper(Context context, Looper looper) { mContext = context; - mHandler = handler; + mHandler = new H(looper); mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mDefaultConfig = readDefaultConfig(context.getResources()); mConfig = mDefaultConfig; mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); - - final IntentFilter filter = new IntentFilter(); - filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); - mContext.registerReceiver(mReceiver, filter); } public static ZenModeConfig readDefaultConfig(Resources resources) { @@ -111,8 +108,11 @@ public class ZenModeHelper { mCallbacks.add(callback); } - public void setAudioManager(AudioManager audioManager) { - mAudioManager = audioManager; + public void onSystemReady() { + mAudioManager = LocalServices.getService(AudioManagerInternal.class); + if (mAudioManager != null) { + mAudioManager.setRingerModeDelegate(this); + } } public int getZenModeListenerInterruptionFilter() { @@ -142,10 +142,10 @@ public class ZenModeHelper { } } - public void requestFromListener(int interruptionFilter) { + public void requestFromListener(ComponentName name, int interruptionFilter) { final int newZen = zenModeFromListenerInterruptionFilter(interruptionFilter, -1); if (newZen != -1) { - setZenMode(newZen, "listener"); + setZenMode(newZen, "listener:" + (name != null ? name.flattenToShortString() : null)); } } @@ -214,12 +214,13 @@ public class ZenModeHelper { } public void updateZenMode() { - final int mode = Global.getInt(mContext.getContentResolver(), + final int oldMode = mZenMode; + final int newMode = Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF); - if (mode != mZenMode) { - ZenLog.traceUpdateZenMode(mZenMode, mode); + if (oldMode != newMode) { + ZenLog.traceUpdateZenMode(oldMode, newMode); } - mZenMode = mode; + mZenMode = newMode; final boolean zen = mZenMode != Global.ZEN_MODE_OFF; final String[] exceptionPackages = null; // none (for now) @@ -241,29 +242,7 @@ public class ZenModeHelper { muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, exceptionPackages); - // force ringer mode into compliance - if (mAudioManager != null) { - int ringerMode = mAudioManager.getRingerMode(); - int forcedRingerMode = -1; - if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { - if (ringerMode != AudioManager.RINGER_MODE_SILENT) { - mPreviousRingerMode = ringerMode; - if (DEBUG) Slog.d(TAG, "Silencing ringer"); - forcedRingerMode = AudioManager.RINGER_MODE_SILENT; - } - } else { - if (ringerMode == AudioManager.RINGER_MODE_SILENT) { - if (DEBUG) Slog.d(TAG, "Unsilencing ringer"); - forcedRingerMode = mPreviousRingerMode != -1 ? mPreviousRingerMode - : AudioManager.RINGER_MODE_NORMAL; - mPreviousRingerMode = -1; - } - } - if (forcedRingerMode != -1) { - mAudioManager.setRingerMode(forcedRingerMode, false /*checkZen*/); - ZenLog.traceSetRingerMode(forcedRingerMode); - } - } + onZenUpdated(oldMode, newMode); dispatchOnZenModeChanged(); } @@ -303,25 +282,102 @@ public class ZenModeHelper { return true; } - private void handleRingerModeChanged() { - if (mAudioManager != null) { - // follow ringer mode if necessary - final int ringerMode = mAudioManager.getRingerMode(); - int newZen = -1; - if (ringerMode == AudioManager.RINGER_MODE_SILENT) { - if (mZenMode == Global.ZEN_MODE_OFF) { - newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + private void onZenUpdated(int oldZen, int newZen) { + if (mAudioManager == null) return; + if (oldZen == newZen) return; + + // force the ringer mode into compliance + final int ringerModeInternal = mAudioManager.getRingerModeInternal(); + int newRingerModeInternal = ringerModeInternal; + switch (newZen) { + case Global.ZEN_MODE_NO_INTERRUPTIONS: + if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) { + mPreviousRingerMode = ringerModeInternal; + newRingerModeInternal = AudioManager.RINGER_MODE_SILENT; } - } else if ((ringerMode == AudioManager.RINGER_MODE_NORMAL - || ringerMode == AudioManager.RINGER_MODE_VIBRATE) - && mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { - newZen = Global.ZEN_MODE_OFF; - } - if (newZen != -1) { - ZenLog.traceFollowRingerMode(ringerMode, mZenMode, newZen); - setZenMode(newZen, "ringerMode"); - } + break; + case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: + case Global.ZEN_MODE_OFF: + if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { + newRingerModeInternal = mPreviousRingerMode != -1 ? mPreviousRingerMode + : AudioManager.RINGER_MODE_NORMAL; + mPreviousRingerMode = -1; + } + break; + } + if (newRingerModeInternal != -1) { + mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG); + } + } + + @Override // RingerModeDelegate + public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, + int ringerModeExternal) { + final boolean isChange = ringerModeOld != ringerModeNew; + + int ringerModeExternalOut = ringerModeNew; + + int newZen = -1; + switch(ringerModeNew) { + case AudioManager.RINGER_MODE_SILENT: + if (isChange) { + if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) { + newZen = Global.ZEN_MODE_NO_INTERRUPTIONS; + } + } + break; + case AudioManager.RINGER_MODE_VIBRATE: + case AudioManager.RINGER_MODE_NORMAL: + if (mZenMode != Global.ZEN_MODE_OFF) { + ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT; + } + break; + } + if (newZen != -1) { + mHandler.postSetZenMode(newZen, "ringerModeInternal"); + } + + if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) { + ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller, + ringerModeExternal, ringerModeExternalOut); + } + return ringerModeExternalOut; + } + + @Override // RingerModeDelegate + public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, + int ringerModeInternal) { + int ringerModeInternalOut = ringerModeNew; + final boolean isChange = ringerModeOld != ringerModeNew; + final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; + + int newZen = -1; + switch(ringerModeNew) { + case AudioManager.RINGER_MODE_SILENT: + if (isChange) { + if (mZenMode == Global.ZEN_MODE_OFF) { + newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + } + ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE + : AudioManager.RINGER_MODE_NORMAL; + } else { + ringerModeInternalOut = ringerModeInternal; + } + break; + case AudioManager.RINGER_MODE_VIBRATE: + case AudioManager.RINGER_MODE_NORMAL: + if (mZenMode != Global.ZEN_MODE_OFF) { + newZen = Global.ZEN_MODE_OFF; + } + break; + } + if (newZen != -1) { + mHandler.postSetZenMode(newZen, "ringerModeExternal"); } + + ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, ringerModeInternal, + ringerModeInternalOut); + return ringerModeInternalOut; } private void dispatchOnConfigChanged() { @@ -399,6 +455,11 @@ public class ZenModeHelper { return true; } + @Override + public String toString() { + return TAG; + } + private boolean audienceMatches(float contactAffinity) { switch (mConfig.allowFrom) { case ZenModeConfig.SOURCE_ANYONE: @@ -413,13 +474,6 @@ public class ZenModeHelper { } } - private final Runnable mRingerModeChanged = new Runnable() { - @Override - public void run() { - handleRingerModeChanged(); - } - }; - private class SettingsObserver extends ContentObserver { private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE); @@ -445,12 +499,26 @@ public class ZenModeHelper { } } - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + private class H extends Handler { + private static final int MSG_SET_ZEN = 1; + + private H(Looper looper) { + super(looper); + } + + private void postSetZenMode(int zen, String reason) { + obtainMessage(MSG_SET_ZEN, zen, 0, reason).sendToTarget(); + } + @Override - public void onReceive(Context context, Intent intent) { - mHandler.post(mRingerModeChanged); + public void handleMessage(Message msg) { + switch(msg.what) { + case MSG_SET_ZEN: + setZenMode(msg.arg1, (String) msg.obj); + break; + } } - }; + } public static class Callback { void onConfigChanged() {} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6331dfe..2201d2b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -17,6 +17,8 @@ package com.android.server.devicepolicy; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; +import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; +import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA; import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES; import android.accessibilityservice.AccessibilityServiceInfo; @@ -78,6 +80,7 @@ import android.security.IKeyChainService; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; import android.text.TextUtils; +import android.service.persistentdata.PersistentDataBlockManager; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; @@ -96,7 +99,6 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; -import com.android.org.conscrypt.TrustedCertificateStore; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; @@ -1645,12 +1647,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void manageNotification(UserHandle userHandle) { + final UserInfo userInfo = mUserManager.getUserInfo(userHandle.getIdentifier()); + + // Inactive users or managed profiles shouldn't provoke a warning if (!mUserManager.isUserRunning(userHandle)) { return; } + if (userInfo == null || userInfo.isManagedProfile()) { + return; + } + // Call out to KeyChain to check for user-added CAs boolean hasCert = false; - final long id = Binder.clearCallingIdentity(); try { KeyChainConnection kcs = KeyChain.bindAsUser(mContext, userHandle); try { @@ -1666,8 +1674,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Thread.currentThread().interrupt(); } catch (RuntimeException e) { Log.e(LOG_TAG, "Could not connect to KeyChain service", e); - } finally { - Binder.restoreCallingIdentity(id); } if (!hasCert) { getNotificationManager().cancelAsUser( @@ -1675,6 +1681,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } + // Build and show a warning notification int smallIconId; String contentText; final String ownerName = getDeviceOwnerName(); @@ -2925,10 +2932,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } - void wipeDataLocked(int flags, String reason) { + private void wipeDataLocked(boolean wipeExtRequested, String reason) { // If the SD card is encrypted and non-removable, we have to force a wipe. boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted(); - boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0; // Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated. if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) { @@ -2941,9 +2947,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else { try { RecoverySystem.rebootWipeUserData(mContext, reason); - } catch (IOException e) { - Slog.w(LOG_TAG, "Failed requesting data wipe", e); - } catch (SecurityException e) { + } catch (IOException | SecurityException e) { Slog.w(LOG_TAG, "Failed requesting data wipe", e); } } @@ -2962,20 +2966,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_WIPE_DATA); final String source; - if (admin != null && admin.info != null) { - final ComponentName cname = admin.info.getComponent(); - if (cname != null) { - source = cname.flattenToShortString(); - } else { - source = admin.info.getPackageName(); - } + final ComponentName cname = admin.info.getComponent(); + if (cname != null) { + source = cname.flattenToShortString(); } else { - source = "?"; + source = admin.info.getPackageName(); } long ident = Binder.clearCallingIdentity(); try { - wipeDeviceOrUserLocked(flags, userHandle, + if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) { + if (userHandle != UserHandle.USER_OWNER + || !isDeviceOwner(admin.info.getPackageName())) { + throw new SecurityException( + "Only device owner admins can set WIPE_RESET_PROTECTION_DATA"); + } + PersistentDataBlockManager manager = (PersistentDataBlockManager) + mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); + manager.wipe(); + } + boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0; + wipeDeviceOrUserLocked(wipeExtRequested, userHandle, "DevicePolicyManager.wipeData() from " + source); } finally { Binder.restoreCallingIdentity(ident); @@ -2983,9 +2994,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void wipeDeviceOrUserLocked(int flags, final int userHandle, String reason) { + private void wipeDeviceOrUserLocked(boolean wipeExtRequested, final int userHandle, String reason) { if (userHandle == UserHandle.USER_OWNER) { - wipeDataLocked(flags, reason); + wipeDataLocked(wipeExtRequested, reason); } else { mHandler.post(new Runnable() { public void run() { @@ -3137,7 +3148,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (wipeData) { // Call without holding lock. - wipeDeviceOrUserLocked(0, identifier, "reportFailedPasswordAttempt()"); + wipeDeviceOrUserLocked(false, identifier, + "reportFailedPasswordAttempt()"); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 4e6a8ea..b3a696e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -549,20 +549,6 @@ public final class SystemServer { reportWtf("making display ready", e); } - try { - mPackageManagerService.performBootDexOpt(); - } catch (Throwable e) { - reportWtf("performing boot dexopt", e); - } - - try { - ActivityManagerNative.getDefault().showBootMessage( - context.getResources().getText( - com.android.internal.R.string.android_upgrading_starting_apps), - false); - } catch (RemoteException e) { - } - if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { if (!disableStorage && !"0".equals(SystemProperties.get("system_init.startmountservice"))) { @@ -578,7 +564,23 @@ public final class SystemServer { reportWtf("starting Mount Service", e); } } + } + try { + mPackageManagerService.performBootDexOpt(); + } catch (Throwable e) { + reportWtf("performing boot dexopt", e); + } + + try { + ActivityManagerNative.getDefault().showBootMessage( + context.getResources().getText( + com.android.internal.R.string.android_upgrading_starting_apps), + false); + } catch (RemoteException e) { + } + + if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { if (!disableNonCoreServices) { try { Slog.i(TAG, "LockSettingsService"); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 40a8ed4..868b770 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -19,8 +19,11 @@ package android.telephony; import android.annotation.SystemApi; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -3524,4 +3527,48 @@ public class TelephonyManager { } return false; } + + /** + * This function retrieves value for setting "name+subId", and if that is not found + * retrieves value for setting "name", and if that is not found uses def as default + * + * @hide */ + public static int getIntWithSubId(ContentResolver cr, String name, int subId, int def) { + return Settings.Global.getInt(cr, name + subId, Settings.Global.getInt(cr, name, def)); + } + + /** + * This function retrieves value for setting "name+subId", and if that is not found + * retrieves value for setting "name", and if that is not found throws + * SettingNotFoundException + * + * @hide */ + public static int getIntWithSubId(ContentResolver cr, String name, int subId) + throws SettingNotFoundException { + try { + return Settings.Global.getInt(cr, name + subId); + } catch (SettingNotFoundException e) { + try { + int val = Settings.Global.getInt(cr, name); + /* We are now moving from 'setting' to 'setting+subId', and using the value stored + * for 'setting' as default. Reset the default (since it may have a user set + * value). */ + int default_val = val; + if (name.equals(Settings.Global.MOBILE_DATA)) { + default_val = "true".equalsIgnoreCase( + SystemProperties.get("ro.com.android.mobiledata", "true")) ? 1 : 0; + } + + if (default_val != val) { + Settings.Global.putInt(cr, name, default_val); + } + + return val; + } catch (SettingNotFoundException exc) { + throw new SettingNotFoundException(name); + } + } + } } + + |