headphone volume limitation

Limit music volume when headphones or headset are inserted.
Display warning message when user wants to increase the volume
above a platform specific volume and request user acknowledgement
before proceeding.

TODO: exact wording of the warning message must be defined by UX.

Change-Id: I00f429f602534c6d8783126b929371c4d432e6e2
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 4d4e985c..c93da06 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface.OnDismissListener;
 import android.content.BroadcastReceiver;
@@ -92,6 +93,7 @@
     private static final int MSG_REMOTE_VOLUME_CHANGED = 8;
     private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
     private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
+    private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
 
     // Pseudo stream type for master volume
     private static final int STREAM_MASTER = -100;
@@ -211,6 +213,31 @@
     private ToneGenerator mToneGenerators[];
     private Vibrator mVibrator;
 
+    private static AlertDialog sConfirmSafeVolumeDialog;
+
+    private static class WarningDialogReceiver extends BroadcastReceiver
+            implements DialogInterface.OnDismissListener {
+        private Context mContext;
+        private Dialog mDialog;
+
+        WarningDialogReceiver(Context context, Dialog dialog) {
+            mContext = context;
+            mDialog = dialog;
+            IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+            context.registerReceiver(this, filter);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mDialog.cancel();
+        }
+
+        public void onDismiss(DialogInterface unused) {
+            mContext.unregisterReceiver(this);
+        }
+    }
+
+
     public VolumePanel(final Context context, AudioService volumeService) {
         mContext = context;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -528,6 +555,10 @@
         postMuteChanged(STREAM_MASTER, flags);
     }
 
+    public void postDisplaySafeVolumeWarning() {
+        obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, 0, 0).sendToTarget();
+    }
+
     /**
      * Override this if you have other work to do when the volume changes (for
      * example, vibrating, playing a sound, etc.). Make sure to call through to
@@ -796,6 +827,32 @@
         }
     }
 
+    protected void onDisplaySafeVolumeWarning() {
+        if (sConfirmSafeVolumeDialog != null) {
+            sConfirmSafeVolumeDialog.dismiss();
+        }
+        sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
+                .setTitle(android.R.string.dialog_alert_title)
+                .setMessage(com.android.internal.R.string.safe_media_volume_warning)
+                .setPositiveButton(com.android.internal.R.string.yes,
+                                    new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        mAudioService.disableSafeMediaVolume();
+                    }
+                })
+                .setNegativeButton(com.android.internal.R.string.no, null)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .create();
+
+        final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
+                sConfirmSafeVolumeDialog);
+
+        sConfirmSafeVolumeDialog.setOnDismissListener(warning);
+        sConfirmSafeVolumeDialog.getWindow().setType(
+                                                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        sConfirmSafeVolumeDialog.show();
+    }
+
     /**
      * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
      */
@@ -910,6 +967,10 @@
             case MSG_SLIDER_VISIBILITY_CHANGED:
                 onSliderVisibilityChanged(msg.arg1, msg.arg2);
                 break;
+
+            case MSG_DISPLAY_SAFE_VOLUME_WARNING:
+                onDisplaySafeVolumeWarning();
+                break;
         }
     }