diff options
author | Amith Yamasani <yamasani@google.com> | 2011-12-05 19:58:48 -0800 |
---|---|---|
committer | Amith Yamasani <yamasani@google.com> | 2011-12-06 14:48:38 -0800 |
commit | 6243edd818b84adfbe712d5d233d6414b33653ac (patch) | |
tree | 8f6ee51bc79caa36157a05bed45dc7c22805a9bf | |
parent | 40cb30c2df2176c03f24cbdc194e3af5a4f64758 (diff) | |
download | frameworks_base-6243edd818b84adfbe712d5d233d6414b33653ac.zip frameworks_base-6243edd818b84adfbe712d5d233d6414b33653ac.tar.gz frameworks_base-6243edd818b84adfbe712d5d233d6414b33653ac.tar.bz2 |
New and improved silent mode on lockscreen.
3-state item to toggle between Silent/Vibrate/Ringer in long-press power menu.
No volume dialog on lockscreen, unless Power menu is up.
Set VIBRATE_IN_SILENT=1 when upgrading device.
Change-Id: I097d216f96c4abdbd83420e0c477106951b3607d
7 files changed, 267 insertions, 71 deletions
diff --git a/core/res/res/drawable/silent_mode_indicator.xml b/core/res/res/drawable/silent_mode_indicator.xml new file mode 100644 index 0000000..c4e129f --- /dev/null +++ b/core/res/res/drawable/silent_mode_indicator.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="false" android:drawable="@android:color/transparent" /> + <item android:state_selected="true" android:drawable="@drawable/tab_selected_holo" /> +</selector> diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml index 13ab985..694301e 100644 --- a/core/res/res/layout/global_actions_item.xml +++ b/core/res/res/layout/global_actions_item.xml @@ -22,7 +22,7 @@ android:minHeight="?android:attr/listPreferredItemHeight" android:orientation="horizontal" - android:paddingLeft="11dip" + android:paddingLeft="16dip" android:paddingTop="6dip" android:paddingBottom="6dip" > @@ -30,7 +30,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" - android:layout_marginRight="9dip" + android:layout_marginRight="16dip" /> <LinearLayout diff --git a/core/res/res/layout/global_actions_silent_mode.xml b/core/res/res/layout/global_actions_silent_mode.xml new file mode 100644 index 0000000..09b4341 --- /dev/null +++ b/core/res/res/layout/global_actions_silent_mode.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:orientation="horizontal" + > + + <LinearLayout + android:id="@+id/option1" + android:layout_width="64dp" + android:layout_height="match_parent" + android:background="?android:attr/actionBarItemBackground" + > + <ImageView + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:src="@drawable/ic_audio_vol_mute" + android:scaleType="center" + android:duplicateParentState="true" + android:background="@drawable/silent_mode_indicator" + /> + </LinearLayout> + <!-- Spacer --> + <View android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:visibility="invisible"/> + + <LinearLayout + android:id="@+id/option2" + android:layout_width="64dp" + android:layout_height="match_parent" + android:background="?android:attr/actionBarItemBackground" + > + <ImageView + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:src="@drawable/ic_audio_ring_notif_vibrate" + android:scaleType="center" + android:duplicateParentState="true" + android:background="@drawable/silent_mode_indicator" + /> + </LinearLayout> + + <!-- Spacer --> + <View android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:visibility="invisible"/> + + <LinearLayout + android:id="@+id/option3" + android:layout_width="64dp" + android:layout_height="match_parent" + android:background="?android:attr/actionBarItemBackground" + > + <ImageView + android:layout_width="48dp" + android:layout_height="match_parent" + android:layout_gravity="center" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:src="@drawable/ic_audio_vol" + android:scaleType="center" + android:duplicateParentState="true" + android:background="@drawable/silent_mode_indicator" + /> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 228786e..37aacab 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -21,6 +21,7 @@ import static android.media.AudioManager.RINGER_MODE_SILENT; import static android.media.AudioManager.RINGER_MODE_VIBRATE; import android.app.ActivityManagerNative; +import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.bluetooth.BluetoothA2dp; @@ -319,6 +320,8 @@ public class AudioService extends IAudioService.Stub { private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000; // previous volume adjustment direction received by checkForRingerModeChange() private int mPrevVolDirection = AudioManager.ADJUST_SAME; + // Keyguard manager proxy + private KeyguardManager mKeyguardManager; /////////////////////////////////////////////////////////////////////////// // Construction @@ -503,9 +506,10 @@ public class AudioService extends IAudioService.Stub { streamType = getActiveStreamType(suggestedStreamType); } - // Play sounds on STREAM_RING only. + // Play sounds on STREAM_RING only and if lock screen is not on. if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && - ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING))) { + ((STREAM_VOLUME_ALIAS[streamType] != AudioSystem.STREAM_RING) + || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } @@ -2665,6 +2669,8 @@ public class AudioService extends IAudioService.Stub { sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP, 0, 0, null, 0); + mKeyguardManager = + (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; resetBluetoothSco(); getBluetoothHeadset(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 6258652..1fbe08d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -63,7 +63,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 72; + private static final int DATABASE_VERSION = 73; private Context mContext; @@ -961,6 +961,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { + " VALUES(?,?);"); loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, R.bool.def_accessibility_speak_password); + db.setTransactionSuccessful(); } finally { db.endTransaction(); if (stmt != null) stmt.close(); @@ -968,6 +969,23 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 72; } + if (upgradeVersion == 72) { + // update vibration settings + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT OR REPLACE INTO system(name,value)" + + " VALUES(?,?);"); + loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT, + R.bool.def_vibrate_in_silent); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + upgradeVersion = 73; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 3fc53aa..0e2d2a8 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -56,7 +56,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static final String TAG = "GlobalActions"; - private static final boolean SHOW_SILENT_TOGGLE = false; + private static final boolean SHOW_SILENT_TOGGLE = true; private final Context mContext; private final AudioManager mAudioManager; @@ -64,7 +64,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private ArrayList<Action> mItems; private AlertDialog mDialog; - private ToggleAction mSilentModeToggle; + private SilentModeAction mSilentModeAction; private ToggleAction mAirplaneModeOn; private MyAdapter mAdapter; @@ -115,39 +115,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * @return A new dialog. */ private AlertDialog createDialog() { - mSilentModeToggle = new ToggleAction( - R.drawable.ic_audio_vol_mute, - R.drawable.ic_audio_vol, - R.string.global_action_toggle_silent_mode, - R.string.global_action_silent_mode_on_status, - R.string.global_action_silent_mode_off_status) { - - void willCreate() { - mEnabledIconResId = - mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE - ? R.drawable.ic_audio_ring_notif_vibrate - : R.drawable.ic_audio_vol_mute; - } - - void onToggle(boolean on) { - if (on) { - mAudioManager.setRingerMode((Settings.System.getInt(mContext.getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1) - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - } - - public boolean showDuringKeyguard() { - return true; - } - - public boolean showBeforeProvisioning() { - return false; - } - }; + mSilentModeAction = new SilentModeAction(mAudioManager, mHandler); mAirplaneModeOn = new ToggleAction( R.drawable.ic_lock_airplane_mode, @@ -191,15 +159,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mItems = new ArrayList<Action>(); - // silent mode - if (SHOW_SILENT_TOGGLE) { - mItems.add(mSilentModeToggle); - } - - // next: airplane mode - mItems.add(mAirplaneModeOn); - - // last: power off + // first: power off mItems.add( new SinglePressAction( com.android.internal.R.drawable.ic_lock_power_off, @@ -219,13 +179,20 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }); + // next: airplane mode + mItems.add(mAirplaneModeOn); + + // last: silent mode + if (SHOW_SILENT_TOGGLE) { + mItems.add(mSilentModeAction); + } + mAdapter = new MyAdapter(); final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); ab.setAdapter(mAdapter, this) - .setInverseBackgroundForced(true) - .setTitle(R.string.global_actions); + .setInverseBackgroundForced(true); final AlertDialog dialog = ab.create(); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); @@ -238,8 +205,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private void prepareDialog() { final boolean silentModeOn = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - mSilentModeToggle.updateState( - silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); if (mKeyguardShowing) { @@ -247,20 +212,28 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } else { mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); } + if (SHOW_SILENT_TOGGLE) { + IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); + mContext.registerReceiver(mRingerModeReceiver, filter); + } } /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { + if (SHOW_SILENT_TOGGLE) { + mContext.unregisterReceiver(mRingerModeReceiver); + } } /** {@inheritDoc} */ public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); + if (!(mAdapter.getItem(which) instanceof SilentModeAction)) { + dialog.dismiss(); + } mAdapter.getItem(which).onPress(); } - /** * The adapter used for the list within the global actions dialog, taking * into account whether the keyguard is showing via @@ -381,9 +354,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public View create( Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { - View v = (convertView != null) ? - convertView : - inflater.inflate(R.layout.global_actions_item, parent, false); + View v = inflater.inflate(R.layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -460,27 +431,31 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac LayoutInflater inflater) { willCreate(); - View v = (convertView != null) ? - convertView : - inflater.inflate(R + View v = inflater.inflate(R .layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); TextView statusView = (TextView) v.findViewById(R.id.status); + final boolean enabled = isEnabled(); - messageView.setText(mMessageResId); + if (messageView != null) { + messageView.setText(mMessageResId); + messageView.setEnabled(enabled); + } boolean on = ((mState == State.On) || (mState == State.TurningOn)); - icon.setImageDrawable(context.getResources().getDrawable( - (on ? mEnabledIconResId : mDisabledIconResid))); - statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); - statusView.setVisibility(View.VISIBLE); + if (icon != null) { + icon.setImageDrawable(context.getResources().getDrawable( + (on ? mEnabledIconResId : mDisabledIconResid))); + icon.setEnabled(enabled); + } - final boolean enabled = isEnabled(); - messageView.setEnabled(enabled); - statusView.setEnabled(enabled); - icon.setEnabled(enabled); + if (statusView != null) { + statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + statusView.setVisibility(View.VISIBLE); + statusView.setEnabled(enabled); + } v.setEnabled(enabled); return v; @@ -518,6 +493,72 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } + private static class SilentModeAction implements Action, View.OnClickListener { + + private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 }; + + private final AudioManager mAudioManager; + private final Handler mHandler; + + SilentModeAction(AudioManager audioManager, Handler handler) { + mAudioManager = audioManager; + mHandler = handler; + } + + private int ringerModeToIndex(int ringerMode) { + // They just happen to coincide + return ringerMode; + } + + private int indexToRingerMode(int index) { + // They just happen to coincide + return index; + } + + public View create(Context context, View convertView, ViewGroup parent, + LayoutInflater inflater) { + View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false); + // Handle clicks outside the icons and ignore + v.setOnClickListener(this); + + int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode()); + for (int i = 0; i < 3; i++) { + View itemView = v.findViewById(ITEM_IDS[i]); + itemView.setSelected(selectedIndex == i); + // Set up click handler + itemView.setTag(i); + itemView.setOnClickListener(this); + } + return v; + } + + public void onPress() { + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return false; + } + + public boolean isEnabled() { + return true; + } + + void willCreate() { + } + + public void onClick(View v) { + if (!(v.getTag() instanceof Integer)) return; + + int index = (Integer) v.getTag(); + mAudioManager.setRingerMode(indexToRingerMode(index)); + mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY); + } + } + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -549,13 +590,27 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }; + private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { + mHandler.sendEmptyMessage(MESSAGE_REFRESH); + } + } + }; + private static final int MESSAGE_DISMISS = 0; + private static final int MESSAGE_REFRESH = 1; + private static final int DIALOG_DISMISS_DELAY = 300; // ms + private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == MESSAGE_DISMISS) { if (mDialog != null) { mDialog.dismiss(); } + } else if (msg.what == MESSAGE_REFRESH) { + mAdapter.notifyDataSetChanged(); } } }; diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java index de7547b..f204070 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java @@ -49,7 +49,7 @@ public abstract class KeyguardViewBase extends FrameLayout { // Whether the volume keys should be handled by keyguard. If true, then // they will be handled here for specific media types such as music, otherwise // the audio service will bring up the volume dialog. - private static final boolean KEYGUARD_MANAGES_VOLUME = false; + private static final boolean KEYGUARD_MANAGES_VOLUME = true; // This is a faster way to draw the background on devices without hardware acceleration Drawable mBackgroundDrawable = new Drawable() { |