diff options
19 files changed, 547 insertions, 307 deletions
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index e447dbb8a5f2..bb5774f31417 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -16,10 +16,17 @@ package android.view; -import android.bluetooth.HeadsetBase; +import com.android.internal.R; + +import android.app.Dialog; +import android.content.DialogInterface.OnDismissListener; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.AudioService; import android.media.AudioSystem; @@ -29,12 +36,16 @@ import android.net.Uri; import android.os.Handler; import android.os.Message; import android.os.Vibrator; -import android.util.Config; +import android.telephony.TelephonyManager; import android.util.Log; import android.widget.ImageView; import android.widget.ProgressBar; +import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; +import android.widget.SeekBar.OnSeekBarChangeListener; + +import java.util.HashMap; /** * Handle the volume up and down keys. @@ -43,7 +54,7 @@ import android.widget.Toast; * * @hide */ -public class VolumePanel extends Handler +public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener { private static final String TAG = "VolumePanel"; private static boolean LOGD = false; @@ -68,62 +79,255 @@ public class VolumePanel extends Handler private static final int BEEP_DURATION = 150; private static final int MAX_VOLUME = 100; private static final int FREE_DELAY = 10000; + private static final int TIMEOUT_DELAY = 3000; private static final int MSG_VOLUME_CHANGED = 0; private static final int MSG_FREE_RESOURCES = 1; private static final int MSG_PLAY_SOUND = 2; private static final int MSG_STOP_SOUNDS = 3; private static final int MSG_VIBRATE = 4; - - private static final int RINGTONE_VOLUME_TEXT = com.android.internal.R.string.volume_ringtone; - private static final int MUSIC_VOLUME_TEXT = com.android.internal.R.string.volume_music; - private static final int INCALL_VOLUME_TEXT = com.android.internal.R.string.volume_call; - private static final int ALARM_VOLUME_TEXT = com.android.internal.R.string.volume_alarm; - private static final int UNKNOWN_VOLUME_TEXT = com.android.internal.R.string.volume_unknown; - private static final int NOTIFICATION_VOLUME_TEXT = - com.android.internal.R.string.volume_notification; - private static final int BLUETOOTH_INCALL_VOLUME_TEXT = - com.android.internal.R.string.volume_bluetooth_call; + private static final int MSG_TIMEOUT = 5; + private static final int MSG_RINGER_MODE_CHANGED = 6; + +// private static final int RINGTONE_VOLUME_TEXT = com.android.internal.R.string.volume_ringtone; +// private static final int MUSIC_VOLUME_TEXT = com.android.internal.R.string.volume_music; +// private static final int INCALL_VOLUME_TEXT = com.android.internal.R.string.volume_call; +// private static final int ALARM_VOLUME_TEXT = com.android.internal.R.string.volume_alarm; +// private static final int UNKNOWN_VOLUME_TEXT = com.android.internal.R.string.volume_unknown; +// private static final int NOTIFICATION_VOLUME_TEXT = +// com.android.internal.R.string.volume_notification; +// private static final int BLUETOOTH_INCALL_VOLUME_TEXT = +// com.android.internal.R.string.volume_bluetooth_call; protected Context mContext; private AudioManager mAudioManager; protected AudioService mAudioService; private boolean mRingIsSilent; - private final Toast mToast; + /** Dialog containing all the sliders */ + private final Dialog mDialog; + /** Dialog's content view */ private final View mView; - private final TextView mMessage; - private final TextView mAdditionalMessage; - private final ImageView mSmallStreamIcon; - private final ImageView mLargeStreamIcon; - private final ProgressBar mLevel; +// private final TextView mMessage; +// private final TextView mAdditionalMessage; +// private final ImageView mSmallStreamIcon; +// private final ImageView mLargeStreamIcon; +// private final ProgressBar mLevel; + + /** Contains the sliders and their touchable icons */ + private final ViewGroup mSliderGroup; + /** The button that expands the dialog to show all sliders */ + private final View mMoreButton; + /** Dummy divider icon that needs to vanish with the more button */ + private final View mDivider; + + /** Currently active stream that shows up at the top of the list of sliders */ + private int mActiveStreamType = -1; + /** All the slider controls mapped by stream type */ + private HashMap<Integer,StreamControl> mStreamControls; + + // List of stream types and their order + // RING and VOICE_CALL are hidden unless explicitly requested + private static final int [] STREAM_TYPES = { + AudioManager.STREAM_RING, + AudioManager.STREAM_VOICE_CALL, + AudioManager.STREAM_MUSIC, + AudioManager.STREAM_NOTIFICATION + }; + + // These icons need to correspond to the ones above. + private static final int [] STREAM_ICONS_NORMAL = { + R.drawable.ic_audio_phone, + R.drawable.ic_audio_phone, + R.drawable.ic_audio_vol, + R.drawable.ic_audio_notification, + }; + + // These icons need to correspond to the ones above. + private static final int [] STREAM_ICONS_MUTED = { + R.drawable.ic_audio_phone, + R.drawable.ic_audio_phone, + R.drawable.ic_audio_vol_mute, + R.drawable.ic_audio_notification_mute, + }; + + /** Object that contains data for each slider */ + private class StreamControl { + int streamType; + ViewGroup group; + ImageView icon; + SeekBar seekbarView; + int iconRes; + int iconMuteRes; + } // Synchronize when accessing this private ToneGenerator mToneGenerators[]; private Vibrator mVibrator; - public VolumePanel(Context context, AudioService volumeService) { + public VolumePanel(final Context context, AudioService volumeService) { mContext = context; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioService = volumeService; - mToast = new Toast(context); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = mView = inflater.inflate(com.android.internal.R.layout.volume_adjust, null); - mMessage = (TextView) view.findViewById(com.android.internal.R.id.message); - mAdditionalMessage = - (TextView) view.findViewById(com.android.internal.R.id.additional_message); - mSmallStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon); - mLargeStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon); - mLevel = (ProgressBar) view.findViewById(com.android.internal.R.id.level); + View view = mView = inflater.inflate(R.layout.volume_adjust, null); + mView.setOnTouchListener(new View.OnTouchListener() { + public boolean onTouch(View v, MotionEvent event) { + resetTimeout(); + return true; + } + }); + mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group); + mMoreButton = (ImageView) mView.findViewById(R.id.expand_button); + mMoreButton.setOnClickListener(this); + mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider); + + mDialog = new Dialog(context, R.style.Theme_Panel_Volume); + mDialog.setTitle("Volume control"); // No need to localize + mDialog.setContentView(mView); + mDialog.setOnDismissListener(new OnDismissListener() { + public void onDismiss(DialogInterface dialog) { + mActiveStreamType = -1; + } + }); + // Change some window properties + Window window = mDialog.getWindow(); + window.setGravity(Gravity.TOP); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.token = null; + lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + window.setAttributes(lp); + window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + +// mMessage = (TextView) view.findViewById(com.android.internal.R.id.message); +// mAdditionalMessage = +// (TextView) view.findViewById(com.android.internal.R.id.additional_message); +// mSmallStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.other_stream_icon); +// mLargeStreamIcon = (ImageView) view.findViewById(com.android.internal.R.id.ringer_stream_icon); +// mLevel = (ProgressBar) view.findViewById(com.android.internal.R.id.level); mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mVibrator = new Vibrator(); + + listenToRingerMode(); + } + + private void listenToRingerMode() { + final IntentFilter filter = new IntentFilter(); + filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); + mContext.registerReceiver(new BroadcastReceiver() { + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { + removeMessages(MSG_RINGER_MODE_CHANGED); + sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED)); + } + } + }, filter); + } + + private boolean isMuted(int streamType) { + return mAudioManager.isStreamMute(streamType); + } + + private void createSliders() { + LayoutInflater inflater = (LayoutInflater) mContext + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mStreamControls = new HashMap<Integer,StreamControl>(STREAM_TYPES.length); + for (int i = 0; i < STREAM_TYPES.length; i++) { + StreamControl sc = new StreamControl(); + sc.streamType = STREAM_TYPES[i]; + sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null); + sc.group.setTag(sc); + sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon); + sc.icon.setOnClickListener(this); + sc.icon.setTag(sc); + sc.iconRes = STREAM_ICONS_NORMAL[i]; + sc.iconMuteRes = STREAM_ICONS_MUTED[i]; + sc.icon.setImageResource(sc.iconRes); + sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar); + sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(STREAM_TYPES[i])); + sc.seekbarView.setOnSeekBarChangeListener(this); + sc.seekbarView.setTag(sc); + mStreamControls.put(STREAM_TYPES[i], sc); + } + } + + private void reorderSliders(int activeStreamType) { + mSliderGroup.removeAllViews(); + + StreamControl active = mStreamControls.get(activeStreamType); + if (active == null) { + Log.e("VolumePanel", "Missing stream type! - " + activeStreamType); + mActiveStreamType = -1; + } else { + mSliderGroup.addView(active.group); + mActiveStreamType = activeStreamType; + active.group.setVisibility(View.VISIBLE); + updateSlider(active); + } + + for (int i = 0; i < STREAM_TYPES.length; i++) { + // Skip the phone specific ones and the active one + final int streamType = STREAM_TYPES[i]; + if (streamType == AudioManager.STREAM_RING + || streamType == AudioManager.STREAM_VOICE_CALL + || streamType == activeStreamType) { + continue; + } + StreamControl sc = mStreamControls.get(streamType); + mSliderGroup.addView(sc.group); + updateSlider(sc); + } + } + + /** Update the mute and progress state of a slider */ + private void updateSlider(StreamControl sc) { + sc.seekbarView.setProgress(mAudioManager.getLastAudibleStreamVolume(sc.streamType)); + final boolean muted = isMuted(sc.streamType); + sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes); + sc.seekbarView.setEnabled(!muted); + } + + private boolean isExpanded() { + return mMoreButton.getVisibility() != View.VISIBLE; + } + + private void expand() { + final int count = mSliderGroup.getChildCount(); + for (int i = 0; i < count; i++) { + mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE); + } + mMoreButton.setVisibility(View.INVISIBLE); + mDivider.setVisibility(View.INVISIBLE); + } + + private void collapse() { + mMoreButton.setVisibility(View.VISIBLE); + mDivider.setVisibility(View.VISIBLE); + final int count = mSliderGroup.getChildCount(); + for (int i = 1; i < count; i++) { + mSliderGroup.getChildAt(i).setVisibility(View.GONE); + } + } + + private void updateStates() { + final int count = mSliderGroup.getChildCount(); + for (int i = 0; i < count; i++) { + StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag(); + updateSlider(sc); + } } public void postVolumeChanged(int streamType, int flags) { if (hasMessages(MSG_VOLUME_CHANGED)) return; + if (mStreamControls == null) { + createSliders(); + } removeMessages(MSG_FREE_RESOURCES); obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget(); } @@ -137,6 +341,10 @@ public class VolumePanel extends Handler if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")"); + if (mActiveStreamType == -1) { + reorderSliders(streamType); + } + if ((flags & AudioManager.FLAG_SHOW_UI) != 0) { onShowVolumeChanged(streamType, flags); } @@ -154,12 +362,14 @@ public class VolumePanel extends Handler removeMessages(MSG_FREE_RESOURCES); sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY); + + resetTimeout(); } protected void onShowVolumeChanged(int streamType, int flags) { int index = mAudioService.getStreamVolume(streamType); - int message = UNKNOWN_VOLUME_TEXT; - int additionalMessage = 0; +// int message = UNKNOWN_VOLUME_TEXT; +// int additionalMessage = 0; mRingIsSilent = false; if (LOGD) { @@ -168,31 +378,35 @@ public class VolumePanel extends Handler } // get max volume for progress bar + int max = mAudioService.getStreamMaxVolume(streamType); switch (streamType) { case AudioManager.STREAM_RING: { - setRingerIcon(); - message = RINGTONE_VOLUME_TEXT; +// setRingerIcon(); +// message = RINGTONE_VOLUME_TEXT; Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri( mContext, RingtoneManager.TYPE_RINGTONE); if (ringuri == null) { - additionalMessage = - com.android.internal.R.string.volume_music_hint_silent_ringtone_selected; +// additionalMessage = +// com.android.internal.R.string.volume_music_hint_silent_ringtone_selected; mRingIsSilent = true; } break; } case AudioManager.STREAM_MUSIC: { - message = MUSIC_VOLUME_TEXT; +// message = MUSIC_VOLUME_TEXT; + // Special case for when Bluetooth is active for music if (mAudioManager.isBluetoothA2dpOn()) { - additionalMessage = - com.android.internal.R.string.volume_music_hint_playing_through_bluetooth; - setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_ad2p); +// additionalMessage = +// com.android.internal.R.string.volume_music_hint_playing_through_bluetooth; +// setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_ad2p); + setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute); } else { - setSmallIcon(index); + setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute); +// setSmallIcon(index); } break; } @@ -205,25 +419,25 @@ public class VolumePanel extends Handler */ index++; max++; - message = INCALL_VOLUME_TEXT; - setSmallIcon(index); +// message = INCALL_VOLUME_TEXT; +// setSmallIcon(index); break; } case AudioManager.STREAM_ALARM: { - message = ALARM_VOLUME_TEXT; - setSmallIcon(index); +// message = ALARM_VOLUME_TEXT; +// setSmallIcon(index); break; } case AudioManager.STREAM_NOTIFICATION: { - message = NOTIFICATION_VOLUME_TEXT; - setSmallIcon(index); +// message = NOTIFICATION_VOLUME_TEXT; +// setSmallIcon(index); Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri( mContext, RingtoneManager.TYPE_NOTIFICATION); if (ringuri == null) { - additionalMessage = - com.android.internal.R.string.volume_music_hint_silent_ringtone_selected; +// additionalMessage = +// com.android.internal.R.string.volume_music_hint_silent_ringtone_selected; mRingIsSilent = true; } break; @@ -237,33 +451,40 @@ public class VolumePanel extends Handler */ index++; max++; - message = BLUETOOTH_INCALL_VOLUME_TEXT; - setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call); +// message = BLUETOOTH_INCALL_VOLUME_TEXT; +// setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call); break; } } - String messageString = Resources.getSystem().getString(message); - if (!mMessage.getText().equals(messageString)) { - mMessage.setText(messageString); +// String messageString = Resources.getSystem().getString(message); +// if (!mMessage.getText().equals(messageString)) { +// mMessage.setText(messageString); +// } +// +// if (additionalMessage == 0) { +// mAdditionalMessage.setVisibility(View.GONE); +// } else { +// mAdditionalMessage.setVisibility(View.VISIBLE); +// mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage)); +// } + +// if (max != mLevel.getMax()) { +// mLevel.setMax(max); +// } +// mLevel.setProgress(index); + + StreamControl sc = mStreamControls.get(streamType); + if (sc != null) { + sc.seekbarView.setProgress(index); } - if (additionalMessage == 0) { - mAdditionalMessage.setVisibility(View.GONE); - } else { - mAdditionalMessage.setVisibility(View.VISIBLE); - mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage)); - } - - if (max != mLevel.getMax()) { - mLevel.setMax(max); + if (!mDialog.isShowing()) { + mDialog.setContentView(mView); + // Showing dialog - use collapsed state + collapse(); + mDialog.show(); } - mLevel.setProgress(index); - - mToast.setView(mView); - mToast.setDuration(Toast.LENGTH_SHORT); - mToast.setGravity(Gravity.TOP, 0, 0); - mToast.show(); // Do a little vibrate if applicable (only when going into vibrate mode) if ((flags & AudioManager.FLAG_VIBRATE) != 0 && @@ -333,59 +554,72 @@ public class VolumePanel extends Handler } } - /** - * Makes the small icon visible, and hides the large icon. - * - * @param index The volume index, where 0 means muted. - */ - private void setSmallIcon(int index) { - mLargeStreamIcon.setVisibility(View.GONE); - mSmallStreamIcon.setVisibility(View.VISIBLE); - - mSmallStreamIcon.setImageResource(index == 0 - ? com.android.internal.R.drawable.ic_volume_off_small - : com.android.internal.R.drawable.ic_volume_small); - } - - /** - * Makes the large image view visible with the given icon. - * - * @param resId The icon to display. - */ - private void setLargeIcon(int resId) { - mSmallStreamIcon.setVisibility(View.GONE); - mLargeStreamIcon.setVisibility(View.VISIBLE); - mLargeStreamIcon.setImageResource(resId); - } +// /** +// * Makes the small icon visible, and hides the large icon. +// * +// * @param index The volume index, where 0 means muted. +// */ +// private void setSmallIcon(int index) { +// mLargeStreamIcon.setVisibility(View.GONE); +// mSmallStreamIcon.setVisibility(View.VISIBLE); +// +// mSmallStreamIcon.setImageResource(index == 0 +// ? com.android.internal.R.drawable.ic_volume_off_small +// : com.android.internal.R.drawable.ic_volume_small); +// } +// +// /** +// * Makes the large image view visible with the given icon. +// * +// * @param resId The icon to display. +// */ +// private void setLargeIcon(int resId) { +// mSmallStreamIcon.setVisibility(View.GONE); +// mLargeStreamIcon.setVisibility(View.VISIBLE); +// mLargeStreamIcon.setImageResource(resId); +// } +// +// /** +// * Makes the ringer icon visible with an icon that is chosen +// * based on the current ringer mode. +// */ +// private void setRingerIcon() { +// mSmallStreamIcon.setVisibility(View.GONE); +// mLargeStreamIcon.setVisibility(View.VISIBLE); +// +// int ringerMode = mAudioService.getRingerMode(); +// int icon; +// +// if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode); +// +// if (ringerMode == AudioManager.RINGER_MODE_SILENT) { +// icon = com.android.internal.R.drawable.ic_volume_off; +// } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { +// icon = com.android.internal.R.drawable.ic_vibrate; +// } else { +// icon = com.android.internal.R.drawable.ic_volume; +// } +// mLargeStreamIcon.setImageResource(icon); +// } /** - * Makes the ringer icon visible with an icon that is chosen - * based on the current ringer mode. + * Switch between icons because Bluetooth music is same as music volume, but with + * different icons. */ - private void setRingerIcon() { - mSmallStreamIcon.setVisibility(View.GONE); - mLargeStreamIcon.setVisibility(View.VISIBLE); - - int ringerMode = mAudioService.getRingerMode(); - int icon; - - if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode); - - if (ringerMode == AudioManager.RINGER_MODE_SILENT) { - icon = com.android.internal.R.drawable.ic_volume_off; - } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { - icon = com.android.internal.R.drawable.ic_vibrate; - } else { - icon = com.android.internal.R.drawable.ic_volume; + private void setMusicIcon(int resId, int resMuteId) { + StreamControl sc = mStreamControls.get(AudioManager.STREAM_MUSIC); + if (sc != null) { + sc.iconRes = resId; + sc.iconMuteRes = resMuteId; + sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes); } - mLargeStreamIcon.setImageResource(icon); } protected void onFreeResources() { // We'll keep the views, just ditch the cached drawable and hence // bitmaps - mSmallStreamIcon.setImageDrawable(null); - mLargeStreamIcon.setImageDrawable(null); +// mSmallStreamIcon.setImageDrawable(null); +// mLargeStreamIcon.setImageDrawable(null); synchronized (this) { for (int i = mToneGenerators.length - 1; i >= 0; i--) { @@ -426,7 +660,55 @@ public class VolumePanel extends Handler break; } + case MSG_TIMEOUT: { + if (mDialog.isShowing()) { + mDialog.dismiss(); + mActiveStreamType = -1; + } + break; + } + case MSG_RINGER_MODE_CHANGED: { + if (mDialog.isShowing()) { + updateStates(); + } + break; + } } } + private void resetTimeout() { + removeMessages(MSG_TIMEOUT); + sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY); + } + + public void onProgressChanged(SeekBar seekBar, int progress, + boolean fromUser) { + final Object tag = seekBar.getTag(); + if (fromUser && tag instanceof StreamControl) { + StreamControl sc = (StreamControl) tag; + if (mAudioManager.getStreamVolume(sc.streamType) != progress) { + mAudioManager.setStreamVolume(sc.streamType, progress, 0); + } + } + resetTimeout(); + } + + public void onStartTrackingTouch(SeekBar seekBar) { + } + + public void onStopTrackingTouch(SeekBar seekBar) { + } + + public void onClick(View v) { + if (v == mMoreButton) { + expand(); + } else if (v.getTag() instanceof StreamControl) { + StreamControl sc = (StreamControl) v.getTag(); + mAudioManager.setRingerMode(mAudioManager.isSilentMode() + ? AudioManager.RINGER_MODE_NORMAL : AudioManager.RINGER_MODE_SILENT); + // Expand the dialog if it hasn't been expanded yet. + if (!isExpanded()) expand(); + } + resetTimeout(); + } } diff --git a/core/res/res/drawable-hdpi/ic_audio_vol.png b/core/res/res/drawable-hdpi/ic_audio_vol.png Binary files differindex cf3f3f54c514..6ea269330dd5 100644 --- a/core/res/res/drawable-hdpi/ic_audio_vol.png +++ b/core/res/res/drawable-hdpi/ic_audio_vol.png diff --git a/core/res/res/drawable-hdpi/ic_audio_vol_mute.png b/core/res/res/drawable-hdpi/ic_audio_vol_mute.png Binary files differindex c4ac4ef56618..f7428c7f1ba1 100644 --- a/core/res/res/drawable-hdpi/ic_audio_vol_mute.png +++ b/core/res/res/drawable-hdpi/ic_audio_vol_mute.png diff --git a/core/res/res/drawable-hdpi/ic_sysbar_quicksettings.png b/core/res/res/drawable-hdpi/ic_sysbar_quicksettings.png Binary files differnew file mode 100644 index 000000000000..47b4ba23f7a5 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_sysbar_quicksettings.png diff --git a/core/res/res/drawable-mdpi/ic_audio_vol.png b/core/res/res/drawable-mdpi/ic_audio_vol.png Binary files differindex 049e92ab4126..c32fdbc0d70c 100644 --- a/core/res/res/drawable-mdpi/ic_audio_vol.png +++ b/core/res/res/drawable-mdpi/ic_audio_vol.png diff --git a/core/res/res/drawable-mdpi/ic_audio_vol_mute.png b/core/res/res/drawable-mdpi/ic_audio_vol_mute.png Binary files differindex be71492984b3..52611b6c3b91 100644 --- a/core/res/res/drawable-mdpi/ic_audio_vol_mute.png +++ b/core/res/res/drawable-mdpi/ic_audio_vol_mute.png diff --git a/core/res/res/drawable-mdpi/ic_sysbar_quicksettings.png b/core/res/res/drawable-mdpi/ic_sysbar_quicksettings.png Binary files differnew file mode 100644 index 000000000000..792810427f92 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_sysbar_quicksettings.png diff --git a/core/res/res/layout/volume_adjust.xml b/core/res/res/layout/volume_adjust.xml index 18da85f93d9a..b0ca3e8e71ff 100644 --- a/core/res/res/layout/volume_adjust.xml +++ b/core/res/res/layout/volume_adjust.xml @@ -17,56 +17,48 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@android:drawable/dialog_full_holo_dark" android:gravity="left"> <LinearLayout - android:layout_width="416dip" - android:layout_height="wrap_content" - android:paddingLeft="16dip" - android:paddingTop="16dip" - android:paddingRight="16dip" - android:paddingBottom="8dip" - android:orientation="vertical"> - - <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="8dip" - android:gravity="left"> - - <ImageView - android:id="@+id/other_stream_icon" + android:layout_marginTop="80dip" + android:background="@android:drawable/dialog_full_holo_dark" + android:orientation="horizontal" + > + + <LinearLayout + android:id="@+id/slider_group" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginRight="16dip" /> + android:orientation="vertical" + > + <!-- Sliders go here --> + </LinearLayout> - <TextView + <ImageView + android:id="@+id/expand_button_divider" + android:src="?attr/dividerVertical" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/message" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:layout_height="32dip" + android:scaleType="fitXY" + android:layout_gravity="top" + android:layout_marginTop="16dip" + android:layout_marginBottom="16dip" + /> + <ImageView + android:id="@+id/expand_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:padding="16dip" + android:background="?attr/selectableItemBackground" + android:src="@drawable/ic_sysbar_quicksettings" + /> + </LinearLayout> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/additional_message" - android:textAppearance="?android:attr/textAppearanceSmall" /> - - <ImageView - android:id="@+id/ringer_stream_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="14dip" /> - - <ProgressBar - style="?android:attr/progressBarStyleHorizontal" - android:id="@+id/level" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </LinearLayout> </FrameLayout> diff --git a/core/res/res/layout/volume_adjust_item.xml b/core/res/res/layout/volume_adjust_item.xml new file mode 100644 index 000000000000..e841d878af0c --- /dev/null +++ b/core/res/res/layout/volume_adjust_item.xml @@ -0,0 +1,45 @@ +<?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="80dip" + android:orientation="horizontal" + android:layout_marginTop="8dip" + android:layout_marginBottom="8dip" + android:gravity="left|center_vertical"> + + <ImageView + android:id="@+id/stream_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="16dip" + android:layout_marginLeft="8dip" + android:background="?attr/selectableItemBackground" + /> + + <SeekBar + style="?android:attr/seekBarStyle" + android:id="@+id/seekbar" + android:layout_width="300dip" + android:layout_height="wrap_content" + android:padding="16dip" + android:layout_marginLeft="8dip" + android:layout_marginRight="8dip" /> + +</LinearLayout> + + diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index e2751bd59029..5700641f3986 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -208,6 +208,11 @@ <item name="windowExitAnimation">@anim/fade_out</item> </style> + <!-- Window animations used for volume panel. --> + <style name="Animation.VolumePanel"> + <item name="windowEnterAnimation">@null</item> + <item name="windowExitAnimation">@anim/fade_out</item> + </style> <!-- Status Bar Styles --> <style name="TextAppearance.StatusBar"> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 38b068e25c95..6d5b4822b1dc 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -730,6 +730,11 @@ <item name="android:windowCloseOnTouchOutside">false</item> </style> + <style name="Theme.Panel.Volume"> + <item name="android:windowAnimationStyle">@android:style/Animation.VolumePanel</item> + <item name="android:windowCloseOnTouchOutside">true</item> + </style> + <!-- Default theme with an Action Bar. --> <style name="Theme.WithActionBar"> <item name="android:windowActionBar">true</item> diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index c1deed38ae95..136e9b4cf74b 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -104,7 +104,7 @@ public class Canvas { public Canvas() { // 0 means no native bitmap mNativeCanvas = initRaster(0); - mFinalizer = new CanvasFinalizer(0); + mFinalizer = new CanvasFinalizer(mNativeCanvas); } /** diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index ebf7aa0a3d04..4f5edd575926 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -76,8 +76,14 @@ void Caches::dumpMemoryUsage() { LOGD(" PathCache %8d / %8d", pathCache.getSize(), pathCache.getMaxSize()); LOGD(" CircleShapeCache %8d / %8d", circleShapeCache.getSize(), circleShapeCache.getMaxSize()); + LOGD(" OvalShapeCache %8d / %8d", + ovalShapeCache.getSize(), ovalShapeCache.getMaxSize()); LOGD(" RoundRectShapeCache %8d / %8d", roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize()); + LOGD(" RectShapeCache %8d / %8d", + rectShapeCache.getSize(), rectShapeCache.getMaxSize()); + LOGD(" ArcShapeCache %8d / %8d", + arcShapeCache.getSize(), arcShapeCache.getMaxSize()); LOGD(" TextDropShadowCache %8d / %8d", dropShadowCache.getSize(), dropShadowCache.getMaxSize()); for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { @@ -94,6 +100,11 @@ void Caches::dumpMemoryUsage() { total += gradientCache.getSize(); total += pathCache.getSize(); total += dropShadowCache.getSize(); + total += roundRectShapeCache.getSize(); + total += circleShapeCache.getSize(); + total += ovalShapeCache.getSize(); + total += rectShapeCache.getSize(); + total += arcShapeCache.getSize(); for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) { total += fontRenderer.getFontRendererSize(i); } diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index cfc853cc048b..51c81b0ff48c 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -22,62 +22,6 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -#define PATH_HEAP_SIZE 64 - -/////////////////////////////////////////////////////////////////////////////// -// Helpers -/////////////////////////////////////////////////////////////////////////////// - -PathHeap::PathHeap(): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { -} - -PathHeap::PathHeap(SkFlattenableReadBuffer& buffer): mHeap(PATH_HEAP_SIZE * sizeof(SkPath)) { - int count = buffer.readS32(); - - mPaths.setCount(count); - SkPath** ptr = mPaths.begin(); - SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath)); - - for (int i = 0; i < count; i++) { - new (p) SkPath; - p->unflatten(buffer); - *ptr++ = p; - p++; - } -} - -PathHeap::~PathHeap() { - SkPath** iter = mPaths.begin(); - SkPath** stop = mPaths.end(); - while (iter < stop) { - (*iter)->~SkPath(); - iter++; - } -} - -int PathHeap::append(const SkPath& path) { - SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath)); - new (p) SkPath(path); - *mPaths.append() = p; - return mPaths.count(); -} - -void PathHeap::flatten(SkFlattenableWriteBuffer& buffer) const { - int count = mPaths.count(); - - buffer.write32(count); - SkPath** iter = mPaths.begin(); - SkPath** stop = mPaths.end(); - while (iter < stop) { - (*iter)->flatten(buffer); - iter++; - } -} - -/////////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////////// @@ -143,17 +87,15 @@ DisplayList::~DisplayList() { } mPaints.clear(); + for (size_t i = 0; i < mPaths.size(); i++) { + delete mPaths.itemAt(i); + } + mPaths.clear(); + for (size_t i = 0; i < mMatrices.size(); i++) { delete mMatrices.itemAt(i); } mMatrices.clear(); - - if (mPathHeap) { - for (int i = 0; i < mPathHeap->count(); i++) { - caches.pathCache.removeDeferred(&(*mPathHeap)[i]); - } - mPathHeap->safeUnref(); - } } void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder) { @@ -169,12 +111,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde writer.flatten(buffer); mReader.setMemory(buffer, size); - mRCPlayback.reset(&recorder.mRCRecorder); - mRCPlayback.setupBuffer(mReader); - - mTFPlayback.reset(&recorder.mTFRecorder); - mTFPlayback.setupBuffer(mReader); - Caches& caches = Caches::getInstance(); const Vector<SkBitmap*> &bitmapResources = recorder.getBitmapResources(); @@ -196,19 +132,18 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde mPaints.add(paints.itemAt(i)); } + const Vector<SkPath*> &paths = recorder.getPaths(); + for (size_t i = 0; i < paths.size(); i++) { + mPaths.add(paths.itemAt(i)); + } + const Vector<SkMatrix*> &matrices = recorder.getMatrices(); for (size_t i = 0; i < matrices.size(); i++) { mMatrices.add(matrices.itemAt(i)); } - - mPathHeap = recorder.mPathHeap; - if (mPathHeap) { - mPathHeap->safeRef(); - } } void DisplayList::init() { - mPathHeap = NULL; } bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { @@ -557,9 +492,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { // Base structure /////////////////////////////////////////////////////////////////////////////// -DisplayListRenderer::DisplayListRenderer(): - mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) { - mPathHeap = NULL; +DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE) { mDisplayList = NULL; } @@ -568,16 +501,7 @@ DisplayListRenderer::~DisplayListRenderer() { } void DisplayListRenderer::reset() { - if (mPathHeap) { - mPathHeap->unref(); - mPathHeap = NULL; - } - mWriter.reset(); - mHeap.reset(); - - mRCRecorder.reset(); - mTFRecorder.reset(); Caches& caches = Caches::getInstance(); for (size_t i = 0; i < mBitmapResources.size(); i++) { @@ -594,6 +518,8 @@ void DisplayListRenderer::reset() { mPaints.clear(); mPaintMap.clear(); + mPaths.clear(); + mPathMap.clear(); mMatrices.clear(); } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index a6d2bfe2b1bb..e762dfbd989d 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -38,7 +38,6 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// #define MIN_WRITER_SIZE 16384 -#define HEAP_BLOCK_SIZE 4096 // Debug #if DEBUG_DISPLAY_LIST @@ -48,31 +47,6 @@ namespace uirenderer { #endif /////////////////////////////////////////////////////////////////////////////// -// Helpers -/////////////////////////////////////////////////////////////////////////////// - -class PathHeap: public SkRefCnt { -public: - PathHeap(); - PathHeap(SkFlattenableReadBuffer& buffer); - ~PathHeap(); - - int append(const SkPath& path); - - int count() const { return mPaths.count(); } - - SkPath& operator[](int index) const { - return *mPaths[index]; - } - - void flatten(SkFlattenableWriteBuffer& buffer) const; - -private: - SkChunkAlloc mHeap; - SkTDArray<SkPath*> mPaths; -}; - -/////////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////////// @@ -174,7 +148,7 @@ private: } SkPath* getPath() { - return &(*mPathHeap)[getInt() - 1]; + return (SkPath*) getInt(); } SkPaint* getPaint() { @@ -209,19 +183,15 @@ private: text->mText = (const char*) mReader.skip(length); } - PathHeap* mPathHeap; - Vector<SkBitmap*> mBitmapResources; Vector<SkiaColorFilter*> mFilterResources; Vector<SkPaint*> mPaints; + Vector<SkPath*> mPaths; Vector<SkMatrix*> mMatrices; Vector<SkiaShader*> mShaders; mutable SkFlattenableReadBuffer mReader; - - SkRefCntPlayback mRCPlayback; - SkTypefacePlayback mTFPlayback; }; /////////////////////////////////////////////////////////////////////////////// @@ -317,6 +287,10 @@ public: return mPaints; } + const Vector<SkPath*>& getPaths() const { + return mPaths; + } + const Vector<SkMatrix*>& getMatrices() const { return mMatrices; } @@ -385,11 +359,24 @@ private: mWriter.writePad(text, byteLength); } - inline void addPath(const SkPath* path) { - if (mPathHeap == NULL) { - mPathHeap = new PathHeap(); + inline void addPath(SkPath* path) { + if (!path) { + addInt((int) NULL); + return; + } + + SkPath* pathCopy = mPathMap.valueFor(path); + if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) { + if (pathCopy == NULL) { + pathCopy = path; + } else { + pathCopy = new SkPath(*path); + mPaths.add(pathCopy); + } + mPathMap.add(path, pathCopy); } - addInt(mPathHeap->append(*path)); + + addInt((int) pathCopy); } inline void addPaint(SkPaint* paint) { @@ -457,25 +444,22 @@ private: caches.resourceCache.incrementRefcount(colorFilter); } - SkChunkAlloc mHeap; - Vector<SkBitmap*> mBitmapResources; Vector<SkiaColorFilter*> mFilterResources; Vector<SkPaint*> mPaints; DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap; + Vector<SkPath*> mPaths; + DefaultKeyedVector<SkPath*, SkPath*> mPathMap; + Vector<SkiaShader*> mShaders; DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap; Vector<SkMatrix*> mMatrices; - PathHeap* mPathHeap; SkWriter32 mWriter; - SkRefCntRecorder mRCRecorder; - SkRefCntRecorder mTFRecorder; - DisplayList *mDisplayList; int mRestoreSaveCount; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 28c302e68de8..0f22bea48009 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -65,7 +65,6 @@ void PathCache::clearGarbage() { PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { PathCacheEntry entry(path, paint); - PathTexture* texture = mCache.get(entry); if (!texture) { diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index 8cefc8c6d541..ffccfa257324 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -32,7 +32,7 @@ namespace android { namespace uirenderer { struct ShadowText { - ShadowText(): radius(0), len(0), hash(0), textSize(0.0f), typeface(NULL) { + ShadowText(): radius(0), len(0), textSize(0.0f), typeface(NULL) { } ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText): @@ -42,20 +42,11 @@ struct ShadowText { textSize = paint->getTextSize(); typeface = paint->getTypeface(); - - hash = 0; - uint32_t multiplier = 1; - const char* text = str.string(); - for (uint32_t i = 0; i < len; i++) { - hash += text[i] * multiplier; - uint32_t shifted = multiplier << 5; - multiplier = shifted - multiplier; - } } ShadowText(const ShadowText& shadow): - radius(shadow.radius), len(shadow.len), hash(shadow.hash), - textSize(shadow.textSize), typeface(shadow.typeface), str(shadow.str) { + radius(shadow.radius), len(shadow.len), textSize(shadow.textSize), + typeface(shadow.typeface), str(shadow.str) { } ~ShadowText() { @@ -63,20 +54,17 @@ struct ShadowText { uint32_t radius; uint32_t len; - uint32_t hash; float textSize; SkTypeface* typeface; String8 str; bool operator<(const ShadowText& rhs) const { - LTE_INT(hash) { - LTE_INT(len) { - LTE_INT(radius) { - LTE_FLOAT(textSize) { - if (typeface < rhs.typeface) return true; - else if (typeface == rhs.typeface) { - return str.compare(rhs.str) < 0; - } + LTE_INT(len) { + LTE_INT(radius) { + LTE_FLOAT(textSize) { + if (typeface < rhs.typeface) return true; + else if (typeface == rhs.typeface) { + return str.compare(rhs.str) < 0; } } } diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index ea5e5ccd8e25..697e879207ec 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -293,18 +293,21 @@ sp<ISensorEventConnection> SensorService::createSensorEventConnection() return result; } -void SensorService::cleanupConnection(const wp<SensorEventConnection>& connection) +void SensorService::cleanupConnection(SensorEventConnection* c) { Mutex::Autolock _l(mLock); + const wp<SensorEventConnection> connection(c); size_t size = mActiveSensors.size(); for (size_t i=0 ; i<size ; ) { - SensorRecord* rec = mActiveSensors.valueAt(i); - if (rec && rec->removeConnection(connection)) { - int handle = mActiveSensors.keyAt(i); + int handle = mActiveSensors.keyAt(i); + if (c->hasSensor(handle)) { SensorInterface* sensor = mSensorMap.valueFor( handle ); if (sensor) { - sensor->activate(connection.unsafe_get(), false); + sensor->activate(c, false); } + } + SensorRecord* rec = mActiveSensors.valueAt(i); + if (rec && rec->removeConnection(connection)) { mActiveSensors.removeItemsAt(i, 1); mActiveVirtualSensors.removeItem(handle); delete rec; diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 540c7e2a5fe8..21f12bdbcf42 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -129,7 +129,7 @@ class SensorService : public: static char const* getServiceName() { return "sensorservice"; } - void cleanupConnection(const wp<SensorEventConnection>& connection); + void cleanupConnection(SensorEventConnection* connection); status_t enable(const sp<SensorEventConnection>& connection, int handle); status_t disable(const sp<SensorEventConnection>& connection, int handle); status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns); |