am f3364080: Merge "New and improved silent mode on lockscreen." into ics-mr1

* commit 'f336408000c4be36045401fb4df89528249e7383':
  New and improved silent mode on lockscreen.
This commit is contained in:
Amith Yamasani
2011-12-06 15:37:31 -08:00
committed by Android Git Automerger
7 changed files with 267 additions and 71 deletions

View File

@ -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>

View File

@ -22,7 +22,7 @@
android:minHeight="?android:attr/listPreferredItemHeight" android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingLeft="11dip" android:paddingLeft="16dip"
android:paddingTop="6dip" android:paddingTop="6dip"
android:paddingBottom="6dip" android:paddingBottom="6dip"
> >
@ -30,7 +30,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginRight="9dip" android:layout_marginRight="16dip"
/> />
<LinearLayout <LinearLayout

View File

@ -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>

View File

@ -21,6 +21,7 @@ import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE; import static android.media.AudioManager.RINGER_MODE_VIBRATE;
import android.app.ActivityManagerNative; import android.app.ActivityManagerNative;
import android.app.KeyguardManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException; import android.app.PendingIntent.CanceledException;
import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothA2dp;
@ -319,6 +320,8 @@ public class AudioService extends IAudioService.Stub {
private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000; private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000;
// previous volume adjustment direction received by checkForRingerModeChange() // previous volume adjustment direction received by checkForRingerModeChange()
private int mPrevVolDirection = AudioManager.ADJUST_SAME; private int mPrevVolDirection = AudioManager.ADJUST_SAME;
// Keyguard manager proxy
private KeyguardManager mKeyguardManager;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Construction // Construction
@ -503,9 +506,10 @@ public class AudioService extends IAudioService.Stub {
streamType = getActiveStreamType(suggestedStreamType); 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 && 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; 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, sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP,
0, 0, null, 0); 0, 0, null, 0);
mKeyguardManager =
(KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
resetBluetoothSco(); resetBluetoothSco();
getBluetoothHeadset(); getBluetoothHeadset();

View File

@ -63,7 +63,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // 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 // is properly propagated through your change. Not doing so will result in a loss of user
// settings. // settings.
private static final int DATABASE_VERSION = 72; private static final int DATABASE_VERSION = 73;
private Context mContext; private Context mContext;
@ -961,6 +961,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
+ " VALUES(?,?);"); + " VALUES(?,?);");
loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
R.bool.def_accessibility_speak_password); R.bool.def_accessibility_speak_password);
db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();
if (stmt != null) stmt.close(); if (stmt != null) stmt.close();
@ -968,6 +969,23 @@ public class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 72; 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! // *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) { if (upgradeVersion != currentVersion) {

View File

@ -56,7 +56,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private static final String TAG = "GlobalActions"; 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 Context mContext;
private final AudioManager mAudioManager; private final AudioManager mAudioManager;
@ -64,7 +64,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private ArrayList<Action> mItems; private ArrayList<Action> mItems;
private AlertDialog mDialog; private AlertDialog mDialog;
private ToggleAction mSilentModeToggle; private SilentModeAction mSilentModeAction;
private ToggleAction mAirplaneModeOn; private ToggleAction mAirplaneModeOn;
private MyAdapter mAdapter; private MyAdapter mAdapter;
@ -115,39 +115,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
* @return A new dialog. * @return A new dialog.
*/ */
private AlertDialog createDialog() { private AlertDialog createDialog() {
mSilentModeToggle = new ToggleAction( mSilentModeAction = new SilentModeAction(mAudioManager, mHandler);
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;
}
};
mAirplaneModeOn = new ToggleAction( mAirplaneModeOn = new ToggleAction(
R.drawable.ic_lock_airplane_mode, R.drawable.ic_lock_airplane_mode,
@ -191,15 +159,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mItems = new ArrayList<Action>(); mItems = new ArrayList<Action>();
// silent mode // first: power off
if (SHOW_SILENT_TOGGLE) {
mItems.add(mSilentModeToggle);
}
// next: airplane mode
mItems.add(mAirplaneModeOn);
// last: power off
mItems.add( mItems.add(
new SinglePressAction( new SinglePressAction(
com.android.internal.R.drawable.ic_lock_power_off, 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(); mAdapter = new MyAdapter();
final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
ab.setAdapter(mAdapter, this) ab.setAdapter(mAdapter, this)
.setInverseBackgroundForced(true) .setInverseBackgroundForced(true);
.setTitle(R.string.global_actions);
final AlertDialog dialog = ab.create(); final AlertDialog dialog = ab.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
@ -238,8 +205,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private void prepareDialog() { private void prepareDialog() {
final boolean silentModeOn = final boolean silentModeOn =
mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
mSilentModeToggle.updateState(
silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
mAirplaneModeOn.updateState(mAirplaneState); mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
if (mKeyguardShowing) { if (mKeyguardShowing) {
@ -247,20 +212,28 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
} else { } else {
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); 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} */ /** {@inheritDoc} */
public void onDismiss(DialogInterface dialog) { public void onDismiss(DialogInterface dialog) {
if (SHOW_SILENT_TOGGLE) {
mContext.unregisterReceiver(mRingerModeReceiver);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (!(mAdapter.getItem(which) instanceof SilentModeAction)) {
dialog.dismiss(); dialog.dismiss();
}
mAdapter.getItem(which).onPress(); mAdapter.getItem(which).onPress();
} }
/** /**
* The adapter used for the list within the global actions dialog, taking * The adapter used for the list within the global actions dialog, taking
* into account whether the keyguard is showing via * into account whether the keyguard is showing via
@ -381,9 +354,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
public View create( public View create(
Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
View v = (convertView != null) ? View v = inflater.inflate(R.layout.global_actions_item, parent, false);
convertView :
inflater.inflate(R.layout.global_actions_item, parent, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon); ImageView icon = (ImageView) v.findViewById(R.id.icon);
TextView messageView = (TextView) v.findViewById(R.id.message); TextView messageView = (TextView) v.findViewById(R.id.message);
@ -460,27 +431,31 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
LayoutInflater inflater) { LayoutInflater inflater) {
willCreate(); willCreate();
View v = (convertView != null) ? View v = inflater.inflate(R
convertView :
inflater.inflate(R
.layout.global_actions_item, parent, false); .layout.global_actions_item, parent, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon); ImageView icon = (ImageView) v.findViewById(R.id.icon);
TextView messageView = (TextView) v.findViewById(R.id.message); TextView messageView = (TextView) v.findViewById(R.id.message);
TextView statusView = (TextView) v.findViewById(R.id.status); TextView statusView = (TextView) v.findViewById(R.id.status);
final boolean enabled = isEnabled();
if (messageView != null) {
messageView.setText(mMessageResId); messageView.setText(mMessageResId);
messageView.setEnabled(enabled);
}
boolean on = ((mState == State.On) || (mState == State.TurningOn)); boolean on = ((mState == State.On) || (mState == State.TurningOn));
if (icon != null) {
icon.setImageDrawable(context.getResources().getDrawable( icon.setImageDrawable(context.getResources().getDrawable(
(on ? mEnabledIconResId : mDisabledIconResid))); (on ? mEnabledIconResId : mDisabledIconResid)));
icon.setEnabled(enabled);
}
if (statusView != null) {
statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
statusView.setVisibility(View.VISIBLE); statusView.setVisibility(View.VISIBLE);
final boolean enabled = isEnabled();
messageView.setEnabled(enabled);
statusView.setEnabled(enabled); statusView.setEnabled(enabled);
icon.setEnabled(enabled); }
v.setEnabled(enabled); v.setEnabled(enabled);
return v; 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() { private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); 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_DISMISS = 0;
private static final int MESSAGE_REFRESH = 1;
private static final int DIALOG_DISMISS_DELAY = 300; // ms
private Handler mHandler = new Handler() { private Handler mHandler = new Handler() {
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (msg.what == MESSAGE_DISMISS) { if (msg.what == MESSAGE_DISMISS) {
if (mDialog != null) { if (mDialog != null) {
mDialog.dismiss(); mDialog.dismiss();
} }
} else if (msg.what == MESSAGE_REFRESH) {
mAdapter.notifyDataSetChanged();
} }
} }
}; };

View File

@ -49,7 +49,7 @@ public abstract class KeyguardViewBase extends FrameLayout {
// Whether the volume keys should be handled by keyguard. If true, then // 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 // they will be handled here for specific media types such as music, otherwise
// the audio service will bring up the volume dialog. // 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 // This is a faster way to draw the background on devices without hardware acceleration
Drawable mBackgroundDrawable = new Drawable() { Drawable mBackgroundDrawable = new Drawable() {