John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 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 | |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 17 | package com.android.systemui.volume; |
| 18 | |
| 19 | import android.app.Notification; |
| 20 | import android.app.NotificationManager; |
| 21 | import android.app.PendingIntent; |
| 22 | import android.content.BroadcastReceiver; |
| 23 | import android.content.ComponentName; |
| 24 | import android.content.Context; |
| 25 | import android.content.DialogInterface; |
| 26 | import android.content.DialogInterface.OnClickListener; |
| 27 | import android.content.Intent; |
| 28 | import android.content.IntentFilter; |
| 29 | import android.content.pm.ApplicationInfo; |
| 30 | import android.content.res.Configuration; |
| 31 | import android.media.AudioManager; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 32 | import android.media.session.MediaSessionManager; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 33 | import android.os.Handler; |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 34 | import android.os.SystemProperties; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 35 | import android.provider.Settings; |
| 36 | import android.text.TextUtils; |
| 37 | import android.util.Log; |
| 38 | |
| 39 | import com.android.systemui.R; |
| 40 | import com.android.systemui.SystemUI; |
John Spurlock | 3c4076a | 2015-02-24 12:12:25 -0500 | [diff] [blame] | 41 | import com.android.systemui.qs.tiles.DndTile; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 42 | import com.android.systemui.statusbar.ServiceMonitor; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 43 | import com.android.systemui.statusbar.phone.SystemUIDialog; |
| 44 | import com.android.systemui.statusbar.policy.ZenModeController; |
| 45 | import com.android.systemui.statusbar.policy.ZenModeControllerImpl; |
| 46 | |
| 47 | import java.io.FileDescriptor; |
| 48 | import java.io.PrintWriter; |
| 49 | |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 50 | public class VolumeUI extends SystemUI { |
| 51 | private static final String TAG = "VolumeUI"; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 52 | private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 53 | |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 54 | private static final boolean USE_OLD_VOLUME = SystemProperties.getBoolean("volume.old", false); |
| 55 | |
John Spurlock | 8600534 | 2014-05-23 11:58:00 -0400 | [diff] [blame] | 56 | private final Handler mHandler = new Handler(); |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 57 | private final Receiver mReceiver = new Receiver(); |
| 58 | private final RestorationNotification mRestorationNotification = new RestorationNotification(); |
John Spurlock | 1dad272 | 2014-07-11 11:07:53 -0400 | [diff] [blame] | 59 | |
John Spurlock | f2565a8 | 2014-10-23 20:16:22 -0400 | [diff] [blame] | 60 | private boolean mEnabled; |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 61 | private AudioManager mAudioManager; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 62 | private NotificationManager mNotificationManager; |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 63 | private MediaSessionManager mMediaSessionManager; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 64 | private ServiceMonitor mVolumeControllerService; |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 65 | |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 66 | private VolumePanelComponent mOldVolume; |
| 67 | private VolumeDialogComponent mNewVolume; |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 68 | |
| 69 | @Override |
| 70 | public void start() { |
John Spurlock | f2565a8 | 2014-10-23 20:16:22 -0400 | [diff] [blame] | 71 | mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui); |
| 72 | if (!mEnabled) return; |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 73 | mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 74 | mNotificationManager = |
| 75 | (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 76 | mMediaSessionManager = (MediaSessionManager) mContext |
| 77 | .getSystemService(Context.MEDIA_SESSION_SERVICE); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 78 | final ZenModeController zenController = new ZenModeControllerImpl(mContext, mHandler); |
| 79 | mOldVolume = new VolumePanelComponent(this, mContext, mHandler, zenController); |
| 80 | mNewVolume = new VolumeDialogComponent(this, mContext, null, zenController); |
| 81 | putComponent(VolumeComponent.class, getVolumeComponent()); |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 82 | mReceiver.start(); |
| 83 | mVolumeControllerService = new ServiceMonitor(TAG, LOGD, |
| 84 | mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT, |
| 85 | new ServiceMonitorCallbacks()); |
| 86 | mVolumeControllerService.start(); |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 87 | } |
| 88 | |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 89 | private VolumeComponent getVolumeComponent() { |
| 90 | return USE_OLD_VOLUME ? mOldVolume : mNewVolume; |
| 91 | } |
| 92 | |
John Spurlock | ad494bc | 2014-07-19 15:56:19 -0400 | [diff] [blame] | 93 | @Override |
John Spurlock | 7e6809a | 2014-08-06 16:03:14 -0400 | [diff] [blame] | 94 | protected void onConfigurationChanged(Configuration newConfig) { |
| 95 | super.onConfigurationChanged(newConfig); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 96 | if (!mEnabled) return; |
| 97 | getVolumeComponent().onConfigurationChanged(newConfig); |
John Spurlock | 7e6809a | 2014-08-06 16:03:14 -0400 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | @Override |
John Spurlock | ad494bc | 2014-07-19 15:56:19 -0400 | [diff] [blame] | 101 | public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
John Spurlock | f2565a8 | 2014-10-23 20:16:22 -0400 | [diff] [blame] | 102 | pw.print("mEnabled="); pw.println(mEnabled); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 103 | if (!mEnabled) return; |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 104 | pw.print("mVolumeControllerService="); pw.println(mVolumeControllerService.getComponent()); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 105 | getVolumeComponent().dump(fd, pw, args); |
John Spurlock | ad494bc | 2014-07-19 15:56:19 -0400 | [diff] [blame] | 106 | } |
| 107 | |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 108 | private void setDefaultVolumeController(boolean register) { |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 109 | if (register) { |
John Spurlock | 3c4076a | 2015-02-24 12:12:25 -0500 | [diff] [blame] | 110 | DndTile.setVisible(mContext, false); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 111 | if (LOGD) Log.d(TAG, "Registering default volume controller"); |
| 112 | getVolumeComponent().register(); |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 113 | } else { |
John Spurlock | c72d4cb | 2015-02-26 14:49:55 -0500 | [diff] [blame] | 114 | if (LOGD) Log.d(TAG, "Unregistering default volume controller"); |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 115 | mAudioManager.setVolumeController(null); |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 116 | mMediaSessionManager.setRemoteVolumeController(null); |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 117 | } |
| 118 | } |
| 119 | |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 120 | private String getAppLabel(ComponentName component) { |
| 121 | final String pkg = component.getPackageName(); |
| 122 | try { |
| 123 | final ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(pkg, 0); |
| 124 | final String rt = mContext.getPackageManager().getApplicationLabel(ai).toString(); |
| 125 | if (!TextUtils.isEmpty(rt)) { |
| 126 | return rt; |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 127 | } |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 128 | } catch (Exception e) { |
| 129 | Log.w(TAG, "Error loading app label", e); |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 130 | } |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 131 | return pkg; |
| 132 | } |
| 133 | |
| 134 | private void showServiceActivationDialog(final ComponentName component) { |
| 135 | final SystemUIDialog d = new SystemUIDialog(mContext); |
| 136 | d.setMessage(mContext.getString(R.string.volumeui_prompt_message, getAppLabel(component))); |
| 137 | d.setPositiveButton(R.string.volumeui_prompt_allow, new OnClickListener() { |
| 138 | @Override |
| 139 | public void onClick(DialogInterface dialog, int which) { |
| 140 | mVolumeControllerService.setComponent(component); |
| 141 | } |
| 142 | }); |
| 143 | d.setNegativeButton(R.string.volumeui_prompt_deny, null); |
| 144 | d.show(); |
| 145 | } |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 146 | |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 147 | private final class ServiceMonitorCallbacks implements ServiceMonitor.Callbacks { |
| 148 | @Override |
| 149 | public void onNoService() { |
| 150 | if (LOGD) Log.d(TAG, "onNoService"); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 151 | setDefaultVolumeController(true); |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 152 | mRestorationNotification.hide(); |
John Spurlock | c72d4cb | 2015-02-26 14:49:55 -0500 | [diff] [blame] | 153 | if (!mVolumeControllerService.isPackageAvailable()) { |
| 154 | mVolumeControllerService.setComponent(null); |
| 155 | } |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | @Override |
| 159 | public long onServiceStartAttempt() { |
| 160 | if (LOGD) Log.d(TAG, "onServiceStartAttempt"); |
John Spurlock | c72d4cb | 2015-02-26 14:49:55 -0500 | [diff] [blame] | 161 | // poke the setting to update the uid |
| 162 | mVolumeControllerService.setComponent(mVolumeControllerService.getComponent()); |
John Spurlock | f88d808 | 2015-03-25 18:09:51 -0400 | [diff] [blame^] | 163 | setDefaultVolumeController(false); |
| 164 | getVolumeComponent().dismissNow(); |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 165 | mRestorationNotification.show(); |
| 166 | return 0; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | private final class Receiver extends BroadcastReceiver { |
| 171 | private static final String ENABLE = "com.android.systemui.vui.ENABLE"; |
| 172 | private static final String DISABLE = "com.android.systemui.vui.DISABLE"; |
| 173 | private static final String EXTRA_COMPONENT = "component"; |
| 174 | |
| 175 | public void start() { |
| 176 | final IntentFilter filter = new IntentFilter(); |
| 177 | filter.addAction(ENABLE); |
| 178 | filter.addAction(DISABLE); |
| 179 | mContext.registerReceiver(this, filter, null, mHandler); |
| 180 | } |
| 181 | |
| 182 | @Override |
| 183 | public void onReceive(Context context, Intent intent) { |
| 184 | final String action = intent.getAction(); |
| 185 | final ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT); |
| 186 | final boolean current = component.equals(mVolumeControllerService.getComponent()); |
| 187 | if (ENABLE.equals(action) && component != null) { |
| 188 | if (!current) { |
| 189 | showServiceActivationDialog(component); |
| 190 | } |
| 191 | } |
| 192 | if (DISABLE.equals(action) && component != null) { |
| 193 | if (current) { |
| 194 | mVolumeControllerService.setComponent(null); |
| 195 | } |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | private final class RestorationNotification { |
| 201 | public void hide() { |
| 202 | mNotificationManager.cancel(R.id.notification_volumeui); |
| 203 | } |
| 204 | |
| 205 | public void show() { |
| 206 | final ComponentName component = mVolumeControllerService.getComponent(); |
| 207 | if (component == null) { |
| 208 | Log.w(TAG, "Not showing restoration notification, component not active"); |
| 209 | return; |
| 210 | } |
| 211 | final Intent intent = new Intent(Receiver.DISABLE) |
| 212 | .putExtra(Receiver.EXTRA_COMPONENT, component); |
| 213 | mNotificationManager.notify(R.id.notification_volumeui, |
| 214 | new Notification.Builder(mContext) |
| 215 | .setSmallIcon(R.drawable.ic_ringer_audible) |
| 216 | .setWhen(0) |
| 217 | .setShowWhen(false) |
| 218 | .setOngoing(true) |
| 219 | .setContentTitle(mContext.getString( |
| 220 | R.string.volumeui_notification_title, getAppLabel(component))) |
| 221 | .setContentText(mContext.getString(R.string.volumeui_notification_text)) |
John Spurlock | 0c6ba18 | 2015-02-26 13:42:53 -0500 | [diff] [blame] | 222 | .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, |
| 223 | PendingIntent.FLAG_UPDATE_CURRENT)) |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 224 | .setPriority(Notification.PRIORITY_MIN) |
| 225 | .setVisibility(Notification.VISIBILITY_PUBLIC) |
Alan Viverette | 4a357cd | 2015-03-18 18:37:18 -0700 | [diff] [blame] | 226 | .setColor(mContext.getColor( |
John Spurlock | cdb57ae | 2015-02-11 19:04:11 -0500 | [diff] [blame] | 227 | com.android.internal.R.color.system_notification_accent_color)) |
| 228 | .build()); |
| 229 | } |
| 230 | } |
John Spurlock | 3346a80 | 2014-05-20 16:25:37 -0400 | [diff] [blame] | 231 | } |