1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification; 18 19 import android.app.PendingIntent; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.graphics.drawable.Drawable; 23 import android.media.AudioManager; 24 import android.net.Uri; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import androidx.core.graphics.drawable.IconCompat; 29 import androidx.slice.builders.ListBuilder; 30 import androidx.slice.builders.SliceAction; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.settings.R; 34 import com.android.settings.Utils; 35 import com.android.settings.bluetooth.BluetoothBroadcastDialog; 36 import com.android.settings.media.MediaOutputIndicatorWorker; 37 import com.android.settings.slices.CustomSliceRegistry; 38 import com.android.settings.slices.SliceBackgroundWorker; 39 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 40 import com.android.settingslib.media.BluetoothMediaDevice; 41 import com.android.settingslib.media.MediaDevice; 42 import com.android.settingslib.media.MediaOutputConstants; 43 44 public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceController { 45 private static final String TAG = "MediaVolumePreCtrl"; 46 private static final String KEY_MEDIA_VOLUME = "media_volume"; 47 48 private MediaOutputIndicatorWorker mWorker; 49 private MediaDevice mMediaDevice; 50 private static final String ACTION_LAUNCH_BROADCAST_DIALOG = 51 "android.settings.MEDIA_BROADCAST_DIALOG"; 52 MediaVolumePreferenceController(Context context)53 public MediaVolumePreferenceController(Context context) { 54 super(context, KEY_MEDIA_VOLUME); 55 } 56 57 @Override getAvailabilityStatus()58 public int getAvailabilityStatus() { 59 return mContext.getResources().getBoolean(R.bool.config_show_media_volume) 60 ? AVAILABLE 61 : UNSUPPORTED_ON_DEVICE; 62 } 63 64 @Override isSliceable()65 public boolean isSliceable() { 66 return TextUtils.equals(getPreferenceKey(), KEY_MEDIA_VOLUME); 67 } 68 69 @Override isPublicSlice()70 public boolean isPublicSlice() { 71 return true; 72 } 73 74 @Override useDynamicSliceSummary()75 public boolean useDynamicSliceSummary() { 76 return true; 77 } 78 79 @Override getPreferenceKey()80 public String getPreferenceKey() { 81 return KEY_MEDIA_VOLUME; 82 } 83 84 @Override getAudioStream()85 public int getAudioStream() { 86 return AudioManager.STREAM_MUSIC; 87 } 88 89 @Override getMuteIcon()90 public int getMuteIcon() { 91 return R.drawable.ic_media_stream_off; 92 } 93 94 @VisibleForTesting isSupportEndItem()95 boolean isSupportEndItem() { 96 return getWorker() != null && getWorker().isBroadcastSupported() && isConnectedBLEDevice(); 97 } 98 isConnectedBLEDevice()99 private boolean isConnectedBLEDevice() { 100 if (getWorker() == null) { 101 Log.d(TAG, "The Worker is null"); 102 return false; 103 } 104 mMediaDevice = getWorker().getCurrentConnectedMediaDevice(); 105 if (mMediaDevice != null) { 106 return mMediaDevice.isBLEDevice(); 107 } 108 return false; 109 } 110 111 @Override getSliceEndItem(Context context)112 public SliceAction getSliceEndItem(Context context) { 113 if (!isSupportEndItem()) { 114 Log.d(TAG, "The slice doesn't support end item"); 115 return null; 116 } 117 118 final Intent intent = new Intent(); 119 PendingIntent pi = null; 120 if (getWorker().isDeviceBroadcasting()) { 121 intent.setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME); 122 intent.setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); 123 intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, 124 getWorker().getActiveLocalMediaController().getPackageName()); 125 126 pi = PendingIntent.getBroadcast(context, 0 /* requestCode */, intent, 127 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 128 } else { 129 final CachedBluetoothDevice bluetoothDevice = 130 ((BluetoothMediaDevice) mMediaDevice).getCachedDevice(); 131 if (bluetoothDevice == null) { 132 Log.d(TAG, "The bluetooth device is null"); 133 return null; 134 } 135 intent.setAction(ACTION_LAUNCH_BROADCAST_DIALOG); 136 intent.putExtra(BluetoothBroadcastDialog.KEY_APP_LABEL, 137 Utils.getApplicationLabel(mContext, getWorker().getPackageName())); 138 intent.putExtra(BluetoothBroadcastDialog.KEY_DEVICE_ADDRESS, 139 bluetoothDevice.getAddress()); 140 intent.putExtra(BluetoothBroadcastDialog.KEY_MEDIA_STREAMING, getWorker() != null 141 && getWorker().getActiveLocalMediaController() != null); 142 143 pi = PendingIntent.getActivity(context, 0 /* requestCode */, intent, 144 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 145 } 146 147 final IconCompat icon = getBroadcastIcon(context); 148 149 return SliceAction.createDeeplink(pi, icon, ListBuilder.ICON_IMAGE, getPreferenceKey()); 150 } 151 getBroadcastIcon(Context context)152 private IconCompat getBroadcastIcon(Context context) { 153 final Drawable drawable = context.getDrawable( 154 com.android.settingslib.R.drawable.settings_input_antenna); 155 if (drawable != null) { 156 drawable.setTint(Utils.getColorAccentDefaultColor(context)); 157 return Utils.createIconWithDrawable(drawable); 158 } 159 return null; 160 } 161 getWorker()162 private MediaOutputIndicatorWorker getWorker() { 163 if (mWorker == null) { 164 mWorker = SliceBackgroundWorker.getInstance(getUri()); 165 } 166 return mWorker; 167 } 168 getUri()169 private Uri getUri() { 170 return CustomSliceRegistry.VOLUME_MEDIA_URI; 171 } 172 173 @Override getBackgroundWorkerClass()174 public Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() { 175 return MediaOutputIndicatorWorker.class; 176 } 177 } 178