diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/D.java b/packages/SettingsLib/src/com/android/settingslib/volume/D.java new file mode 100644 index 0000000000000..7e0654d72b47c --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/volume/D.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 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.settingslib.volume; + +import android.util.Log; + +class D { + public static boolean BUG = Log.isLoggable("volume", Log.DEBUG); +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java similarity index 85% rename from packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java rename to packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java index 8b00eee29c6ea..4ed115405f57c 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java +++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.volume; +package com.android.settingslib.volume; import android.app.PendingIntent; import android.content.Context; @@ -27,7 +27,6 @@ import android.media.IRemoteVolumeController; import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; -import android.media.session.MediaSession; import android.media.session.MediaSession.QueueItem; import android.media.session.MediaSession.Token; import android.media.session.MediaSessionManager; @@ -41,7 +40,6 @@ import android.os.RemoteException; import android.util.Log; import java.io.PrintWriter; -import java.io.StringWriter; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -73,16 +71,24 @@ public class MediaSessions { mCallbacks = callbacks; } + /** + * Dump to {@code writer} + */ public void dump(PrintWriter writer) { writer.println(getClass().getSimpleName() + " state:"); - writer.print(" mInit: "); writer.println(mInit); - writer.print(" mRecords.size: "); writer.println(mRecords.size()); + writer.print(" mInit: "); + writer.println(mInit); + writer.print(" mRecords.size: "); + writer.println(mRecords.size()); int i = 0; for (MediaControllerRecord r : mRecords.values()) { dump(++i, writer, r.controller); } } + /** + * init MediaSessions + */ public void init() { if (D.BUG) Log.d(TAG, "init"); // will throw if no permission @@ -97,12 +103,18 @@ public class MediaSessions { mHandler.sendEmptyMessage(H.UPDATE_SESSIONS); } + /** + * Destroy MediaSessions + */ public void destroy() { if (D.BUG) Log.d(TAG, "destroy"); mInit = false; mMgr.removeOnActiveSessionsChangedListener(mSessionsListener); } + /** + * Set volume {@code level} to remote media {@code token} + */ public void setVolume(Token token, int level) { final MediaControllerRecord r = mRecords.get(token); if (r == null) { @@ -113,15 +125,17 @@ public class MediaSessions { r.controller.setVolumeTo(level, 0); } - private void onRemoteVolumeChangedH(MediaSession.Token sessionToken, int flags) { + private void onRemoteVolumeChangedH(Token sessionToken, int flags) { final MediaController controller = new MediaController(mContext, sessionToken); - if (D.BUG) Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " " - + Util.audioManagerFlagsToString(flags)); + if (D.BUG) { + Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " " + + Util.audioManagerFlagsToString(flags)); + } final Token token = controller.getSessionToken(); mCallbacks.onRemoteVolumeChanged(token, flags); } - private void onUpdateRemoteControllerH(MediaSession.Token sessionToken) { + private void onUpdateRemoteControllerH(Token sessionToken) { final MediaController controller = sessionToken != null ? new MediaController(mContext, sessionToken) : null; final String pkg = controller != null ? controller.getPackageName() : null; @@ -191,7 +205,8 @@ public class MediaSessions { if (appLabel.length() > 0) { return appLabel; } - } catch (NameNotFoundException e) { } + } catch (NameNotFoundException e) { + } return pkg; } @@ -240,29 +255,11 @@ public class MediaSessions { } } - public static void dumpMediaSessions(Context context) { - final MediaSessionManager mgr = (MediaSessionManager) context - .getSystemService(Context.MEDIA_SESSION_SERVICE); - try { - final List controllers = mgr.getActiveSessions(null); - final int N = controllers.size(); - if (D.BUG) Log.d(TAG, N + " controllers"); - for (int i = 0; i < N; i++) { - final StringWriter sw = new StringWriter(); - final PrintWriter pw = new PrintWriter(sw, true); - dump(i + 1, pw, controllers.get(i)); - if (D.BUG) Log.d(TAG, sw.toString()); - } - } catch (SecurityException e) { - Log.w(TAG, "Not allowed to get sessions", e); - } - } - private final class MediaControllerRecord extends MediaController.Callback { - private final MediaController controller; + public final MediaController controller; - private boolean sentRemote; - private String name; + public boolean sentRemote; + public String name; private MediaControllerRecord(MediaController controller) { this.controller = controller; @@ -274,8 +271,10 @@ public class MediaSessions { @Override public void onAudioInfoChanged(PlaybackInfo info) { - if (D.BUG) Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info) - + " sentRemote=" + sentRemote); + if (D.BUG) { + Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info) + + " sentRemote=" + sentRemote); + } final boolean remote = isRemote(info); if (!remote && sentRemote) { mCallbacks.onRemoteRemoved(controller.getSessionToken()); @@ -324,22 +323,22 @@ public class MediaSessions { private final OnActiveSessionsChangedListener mSessionsListener = new OnActiveSessionsChangedListener() { - @Override - public void onActiveSessionsChanged(List controllers) { - onActiveSessionsUpdatedH(controllers); - } - }; + @Override + public void onActiveSessionsChanged(List controllers) { + onActiveSessionsUpdatedH(controllers); + } + }; private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() { @Override - public void remoteVolumeChanged(MediaSession.Token sessionToken, int flags) + public void remoteVolumeChanged(Token sessionToken, int flags) throws RemoteException { mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0, sessionToken).sendToTarget(); } @Override - public void updateRemoteController(final MediaSession.Token sessionToken) + public void updateRemoteController(final Token sessionToken) throws RemoteException { mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, sessionToken).sendToTarget(); } @@ -361,18 +360,32 @@ public class MediaSessions { onActiveSessionsUpdatedH(mMgr.getActiveSessions(null)); break; case REMOTE_VOLUME_CHANGED: - onRemoteVolumeChangedH((MediaSession.Token) msg.obj, msg.arg1); + onRemoteVolumeChangedH((Token) msg.obj, msg.arg1); break; case UPDATE_REMOTE_CONTROLLER: - onUpdateRemoteControllerH((MediaSession.Token) msg.obj); + onUpdateRemoteControllerH((Token) msg.obj); break; } } } + /** + * Callback for remote media sessions + */ public interface Callbacks { + /** + * Invoked when remote media session is updated + */ void onRemoteUpdate(Token token, String name, PlaybackInfo pi); + + /** + * Invoked when remote media session is removed + */ void onRemoteRemoved(Token t); + + /** + * Invoked when remote volume is changed + */ void onRemoteVolumeChanged(Token token, int flags); } diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/Util.java b/packages/SettingsLib/src/com/android/settingslib/volume/Util.java new file mode 100644 index 0000000000000..4e770aeb861e9 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/volume/Util.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2019 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.settingslib.volume; + +import android.content.Context; +import android.media.AudioManager; +import android.media.MediaMetadata; +import android.media.VolumeProvider; +import android.media.session.MediaController.PlaybackInfo; +import android.media.session.PlaybackState; +import android.telephony.TelephonyManager; +import android.widget.TextView; + +import java.util.Objects; + +/** + * Static helpers for the volume dialog. + */ +public class Util { + + private static final int[] AUDIO_MANAGER_FLAGS = new int[]{ + AudioManager.FLAG_SHOW_UI, + AudioManager.FLAG_VIBRATE, + AudioManager.FLAG_PLAY_SOUND, + AudioManager.FLAG_ALLOW_RINGER_MODES, + AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE, + AudioManager.FLAG_SHOW_VIBRATE_HINT, + AudioManager.FLAG_SHOW_SILENT_HINT, + AudioManager.FLAG_FROM_KEY, + AudioManager.FLAG_SHOW_UI_WARNINGS, + }; + + private static final String[] AUDIO_MANAGER_FLAG_NAMES = new String[]{ + "SHOW_UI", + "VIBRATE", + "PLAY_SOUND", + "ALLOW_RINGER_MODES", + "REMOVE_SOUND_AND_VIBRATE", + "SHOW_VIBRATE_HINT", + "SHOW_SILENT_HINT", + "FROM_KEY", + "SHOW_UI_WARNINGS", + }; + + /** + * Extract log tag from {@code c} + */ + public static String logTag(Class c) { + final String tag = "vol." + c.getSimpleName(); + return tag.length() < 23 ? tag : tag.substring(0, 23); + } + + /** + * Convert media metadata to string + */ + public static String mediaMetadataToString(MediaMetadata metadata) { + if (metadata == null) return null; + return metadata.getDescription().toString(); + } + + /** + * Convert playback info to string + */ + public static String playbackInfoToString(PlaybackInfo info) { + if (info == null) return null; + final String type = playbackInfoTypeToString(info.getPlaybackType()); + final String vc = volumeProviderControlToString(info.getVolumeControl()); + return String.format("PlaybackInfo[vol=%s,max=%s,type=%s,vc=%s],atts=%s", + info.getCurrentVolume(), info.getMaxVolume(), type, vc, info.getAudioAttributes()); + } + + /** + * Convert type of playback info to string + */ + public static String playbackInfoTypeToString(int type) { + switch (type) { + case PlaybackInfo.PLAYBACK_TYPE_LOCAL: + return "LOCAL"; + case PlaybackInfo.PLAYBACK_TYPE_REMOTE: + return "REMOTE"; + default: + return "UNKNOWN_" + type; + } + } + + /** + * Convert state of playback info to string + */ + public static String playbackStateStateToString(int state) { + switch (state) { + case PlaybackState.STATE_NONE: + return "STATE_NONE"; + case PlaybackState.STATE_STOPPED: + return "STATE_STOPPED"; + case PlaybackState.STATE_PAUSED: + return "STATE_PAUSED"; + case PlaybackState.STATE_PLAYING: + return "STATE_PLAYING"; + default: + return "UNKNOWN_" + state; + } + } + + /** + * Convert volume provider control to string + */ + public static String volumeProviderControlToString(int control) { + switch (control) { + case VolumeProvider.VOLUME_CONTROL_ABSOLUTE: + return "VOLUME_CONTROL_ABSOLUTE"; + case VolumeProvider.VOLUME_CONTROL_FIXED: + return "VOLUME_CONTROL_FIXED"; + case VolumeProvider.VOLUME_CONTROL_RELATIVE: + return "VOLUME_CONTROL_RELATIVE"; + default: + return "VOLUME_CONTROL_UNKNOWN_" + control; + } + } + + /** + * Convert {@link PlaybackState} to string + */ + public static String playbackStateToString(PlaybackState playbackState) { + if (playbackState == null) return null; + return playbackStateStateToString(playbackState.getState()) + " " + playbackState; + } + + /** + * Convert audio manager flags to string + */ + public static String audioManagerFlagsToString(int value) { + return bitFieldToString(value, AUDIO_MANAGER_FLAGS, AUDIO_MANAGER_FLAG_NAMES); + } + + protected static String bitFieldToString(int value, int[] values, String[] names) { + if (value == 0) return ""; + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < values.length; i++) { + if ((value & values[i]) != 0) { + if (sb.length() > 0) sb.append(','); + sb.append(names[i]); + } + value &= ~values[i]; + } + if (value != 0) { + if (sb.length() > 0) sb.append(','); + sb.append("UNKNOWN_").append(value); + } + return sb.toString(); + } + + private static CharSequence emptyToNull(CharSequence str) { + return str == null || str.length() == 0 ? null : str; + } + + /** + * Set text for specific {@link TextView} + */ + public static boolean setText(TextView tv, CharSequence text) { + if (Objects.equals(emptyToNull(tv.getText()), emptyToNull(text))) return false; + tv.setText(text); + return true; + } + + /** + * Return {@code true} if it is voice capable + */ + public static boolean isVoiceCapable(Context context) { + final TelephonyManager telephony = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + return telephony != null && telephony.isVoiceCapable(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java index c6d62181540ed..7edb5a55a9ae6 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Util.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java @@ -16,52 +16,13 @@ package com.android.systemui.volume; -import android.content.Context; import android.media.AudioManager; -import android.media.MediaMetadata; -import android.media.VolumeProvider; -import android.media.session.MediaController.PlaybackInfo; -import android.media.session.PlaybackState; -import android.telephony.TelephonyManager; import android.view.View; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.Objects; /** * Static helpers for the volume dialog. */ -class Util { - - // Note: currently not shown (only used in the text footer) - private static final SimpleDateFormat HMMAA = new SimpleDateFormat("h:mm aa", Locale.US); - - private static int[] AUDIO_MANAGER_FLAGS = new int[] { - AudioManager.FLAG_SHOW_UI, - AudioManager.FLAG_VIBRATE, - AudioManager.FLAG_PLAY_SOUND, - AudioManager.FLAG_ALLOW_RINGER_MODES, - AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE, - AudioManager.FLAG_SHOW_VIBRATE_HINT, - AudioManager.FLAG_SHOW_SILENT_HINT, - AudioManager.FLAG_FROM_KEY, - AudioManager.FLAG_SHOW_UI_WARNINGS, - }; - - private static String[] AUDIO_MANAGER_FLAG_NAMES = new String[] { - "SHOW_UI", - "VIBRATE", - "PLAY_SOUND", - "ALLOW_RINGER_MODES", - "REMOVE_SOUND_AND_VIBRATE", - "SHOW_VIBRATE_HINT", - "SHOW_SILENT_HINT", - "FROM_KEY", - "SHOW_UI_WARNINGS", - }; +class Util extends com.android.settingslib.volume.Util { public static String logTag(Class c) { final String tag = "vol." + c.getSimpleName(); @@ -70,106 +31,19 @@ class Util { public static String ringerModeToString(int ringerMode) { switch (ringerMode) { - case AudioManager.RINGER_MODE_SILENT: return "RINGER_MODE_SILENT"; - case AudioManager.RINGER_MODE_VIBRATE: return "RINGER_MODE_VIBRATE"; - case AudioManager.RINGER_MODE_NORMAL: return "RINGER_MODE_NORMAL"; - default: return "RINGER_MODE_UNKNOWN_" + ringerMode; + case AudioManager.RINGER_MODE_SILENT: + return "RINGER_MODE_SILENT"; + case AudioManager.RINGER_MODE_VIBRATE: + return "RINGER_MODE_VIBRATE"; + case AudioManager.RINGER_MODE_NORMAL: + return "RINGER_MODE_NORMAL"; + default: + return "RINGER_MODE_UNKNOWN_" + ringerMode; } } - public static String mediaMetadataToString(MediaMetadata metadata) { - if (metadata == null) return null; - return metadata.getDescription().toString(); - } - - public static String playbackInfoToString(PlaybackInfo info) { - if (info == null) return null; - final String type = playbackInfoTypeToString(info.getPlaybackType()); - final String vc = volumeProviderControlToString(info.getVolumeControl()); - return String.format("PlaybackInfo[vol=%s,max=%s,type=%s,vc=%s],atts=%s", - info.getCurrentVolume(), info.getMaxVolume(), type, vc, info.getAudioAttributes()); - } - - public static String playbackInfoTypeToString(int type) { - switch (type) { - case PlaybackInfo.PLAYBACK_TYPE_LOCAL: return "LOCAL"; - case PlaybackInfo.PLAYBACK_TYPE_REMOTE: return "REMOTE"; - default: return "UNKNOWN_" + type; - } - } - - public static String playbackStateStateToString(int state) { - switch (state) { - case PlaybackState.STATE_NONE: return "STATE_NONE"; - case PlaybackState.STATE_STOPPED: return "STATE_STOPPED"; - case PlaybackState.STATE_PAUSED: return "STATE_PAUSED"; - case PlaybackState.STATE_PLAYING: return "STATE_PLAYING"; - default: return "UNKNOWN_" + state; - } - } - - public static String volumeProviderControlToString(int control) { - switch (control) { - case VolumeProvider.VOLUME_CONTROL_ABSOLUTE: return "VOLUME_CONTROL_ABSOLUTE"; - case VolumeProvider.VOLUME_CONTROL_FIXED: return "VOLUME_CONTROL_FIXED"; - case VolumeProvider.VOLUME_CONTROL_RELATIVE: return "VOLUME_CONTROL_RELATIVE"; - default: return "VOLUME_CONTROL_UNKNOWN_" + control; - } - } - - public static String playbackStateToString(PlaybackState playbackState) { - if (playbackState == null) return null; - return playbackStateStateToString(playbackState.getState()) + " " + playbackState; - } - - public static String audioManagerFlagsToString(int value) { - return bitFieldToString(value, AUDIO_MANAGER_FLAGS, AUDIO_MANAGER_FLAG_NAMES); - } - - private static String bitFieldToString(int value, int[] values, String[] names) { - if (value == 0) return ""; - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < values.length; i++) { - if ((value & values[i]) != 0) { - if (sb.length() > 0) sb.append(','); - sb.append(names[i]); - } - value &= ~values[i]; - } - if (value != 0) { - if (sb.length() > 0) sb.append(','); - sb.append("UNKNOWN_").append(value); - } - return sb.toString(); - } - - public static String getShortTime(long millis) { - return HMMAA.format(new Date(millis)); - } - - private static CharSequence emptyToNull(CharSequence str) { - return str == null || str.length() == 0 ? null : str; - } - - public static boolean setText(TextView tv, CharSequence text) { - if (Objects.equals(emptyToNull(tv.getText()), emptyToNull(text))) return false; - tv.setText(text); - return true; - } - public static final void setVisOrGone(View v, boolean vis) { if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return; v.setVisibility(vis ? View.VISIBLE : View.GONE); } - - public static final void setVisOrInvis(View v, boolean vis) { - if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return; - v.setVisibility(vis ? View.VISIBLE : View.INVISIBLE); - } - - public static boolean isVoiceCapable(Context context) { - final TelephonyManager telephony = - (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - return telephony != null && telephony.isVoiceCapable(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 32bc01cdfdfee..4c16297154f37 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -53,6 +53,7 @@ import android.util.Log; import android.view.accessibility.AccessibilityManager; import com.android.internal.annotations.GuardedBy; +import com.android.settingslib.volume.MediaSessions; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider;