am 3f468007: Merge "Protect against lack of WRITE_SYSTEM_SETTINGS AppOp" into mnc-dev

* commit '3f468007170d180663af54d2380046f0c2f04543':
  Protect against lack of WRITE_SYSTEM_SETTINGS AppOp
diff --git a/res/values/ids.xml b/res/values/ids.xml
index e2f0ff5..d8f4aa8 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -17,4 +17,5 @@
 <resources>
     <item type="id" name="context_menu_copy_to_clipboard" />
     <item type="id" name="context_menu_edit_before_call" />
+    <item type="id" name="settings_header_sounds_and_vibration" />
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index eec9b0c..5e2476d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -813,4 +813,7 @@
 
     <!-- Shown as a prompt to turn on the phone permission to allow a call to be placed -->
     <string name="permission_place_call">To place a call,\n turn on the Phone permission.</string>
+
+    <!-- Shown as a message that notifies the user that the Phone app cannot write to system settings, which is why the system settings app is being launched directly instead.-->
+    <string name="toast_cannot_write_system_settings">Phone app does not have permission to write to system settings.</string>
 </resources>
diff --git a/src/com/android/dialer/settings/DefaultRingtonePreference.java b/src/com/android/dialer/settings/DefaultRingtonePreference.java
index c12e717..f2648cb 100644
--- a/src/com/android/dialer/settings/DefaultRingtonePreference.java
+++ b/src/com/android/dialer/settings/DefaultRingtonePreference.java
@@ -16,12 +16,17 @@
 
 package com.android.dialer.settings;
 
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.preference.RingtonePreference;
 import android.util.AttributeSet;
+import android.widget.Toast;
+
+import com.android.contacts.common.util.PermissionsUtil;
+import com.android.dialer.R;
 
 /**
  * RingtonePreference which doesn't show default ringtone setting.
@@ -44,6 +49,13 @@
 
     @Override
     protected void onSaveRingtone(Uri ringtoneUri) {
+        if (!PermissionsUtil.hasAppOp(getContext(), AppOpsManager.OPSTR_WRITE_SETTINGS)) {
+            Toast.makeText(
+                    getContext(),
+                    getContext().getResources().getString(R.string.toast_cannot_write_system_settings),
+                    Toast.LENGTH_SHORT).show();
+            return;
+        }
         RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri);
     }
 
diff --git a/src/com/android/dialer/settings/DialerSettingsActivity.java b/src/com/android/dialer/settings/DialerSettingsActivity.java
index d54053b..abf854c 100644
--- a/src/com/android/dialer/settings/DialerSettingsActivity.java
+++ b/src/com/android/dialer/settings/DialerSettingsActivity.java
@@ -1,23 +1,22 @@
 package com.android.dialer.settings;
 
-import com.google.common.collect.Lists;
-
-import android.content.ComponentName;
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
-import android.os.UserHandle;
+import android.os.Process;
 import android.os.UserManager;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceManager;
-import android.preference.PreferenceActivity.Header;
+import android.provider.Settings;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
-import android.text.TextUtils;
+import android.util.Log;
 import android.view.MenuItem;
+import android.widget.Toast;
 
-import com.android.dialer.DialtactsActivity;
+import com.android.contacts.common.util.PermissionsUtil;
 import com.android.dialer.R;
 
 import java.util.List;
@@ -26,8 +25,6 @@
 
     protected SharedPreferences mPreferences;
 
-    private static final int OWNER_HANDLE_ID = 0;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -44,6 +41,7 @@
         Header soundSettingsHeader = new Header();
         soundSettingsHeader.titleRes = R.string.sounds_and_vibration_title;
         soundSettingsHeader.fragment = SoundSettingsFragment.class.getName();
+        soundSettingsHeader.id = R.id.settings_header_sounds_and_vibration;
         target.add(soundSettingsHeader);
 
         Header quickResponseSettingsHeader = new Header();
@@ -91,6 +89,24 @@
     }
 
     @Override
+    public void onHeaderClick(Header header, int position) {
+        if (header.id == R.id.settings_header_sounds_and_vibration) {
+            // If we don't have the AppOp to write to system settings, go to system sound settings
+            // instead. Otherwise, perform the super implementation (which launches our own
+            // preference fragment.
+            if (!PermissionsUtil.hasAppOp(this, AppOpsManager.OPSTR_WRITE_SETTINGS)) {
+                Toast.makeText(
+                        this,
+                        getResources().getString(R.string.toast_cannot_write_system_settings),
+                        Toast.LENGTH_SHORT).show();
+                startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
+                return;
+            }
+        }
+        super.onHeaderClick(header, position);
+    }
+
+    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (item.getItemId() == android.R.id.home) {
             onBackPressed();
diff --git a/src/com/android/dialer/settings/SoundSettingsFragment.java b/src/com/android/dialer/settings/SoundSettingsFragment.java
index 7fc9394..1dedcaa 100644
--- a/src/com/android/dialer/settings/SoundSettingsFragment.java
+++ b/src/com/android/dialer/settings/SoundSettingsFragment.java
@@ -16,7 +16,9 @@
 
 package com.android.dialer.settings;
 
+import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.Intent;
 import android.media.RingtoneManager;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,7 +32,10 @@
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
+import android.view.MenuItem;
+import android.widget.Toast;
 
+import com.android.contacts.common.util.PermissionsUtil;
 import com.android.dialer.R;
 import com.android.phone.common.util.SettingsUtil;
 
@@ -127,6 +132,13 @@
     public void onResume() {
         super.onResume();
 
+        if (!PermissionsUtil.hasAppOp(getContext(), AppOpsManager.OPSTR_WRITE_SETTINGS)) {
+            // If the user launches this setting fragment, then toggles the WRITE_SYSTEM_SETTINGS
+            // AppOp, then close the fragment since there is nothing useful to do.
+            getActivity().onBackPressed();
+            return;
+        }
+
         if (mVibrateWhenRinging != null) {
             mVibrateWhenRinging.setChecked(shouldVibrateWhenRinging());
         }
@@ -143,6 +155,14 @@
      */
     @Override
     public boolean onPreferenceChange(Preference preference, Object objValue) {
+        if (!PermissionsUtil.hasAppOp(getContext(), AppOpsManager.OPSTR_WRITE_SETTINGS)) {
+            // A user shouldn't be able to get here, but this protects against monkey crashes.
+            Toast.makeText(
+                    getContext(),
+                    getResources().getString(R.string.toast_cannot_write_system_settings),
+                    Toast.LENGTH_SHORT).show();
+            return true;
+        }
         if (preference == mVibrateWhenRinging) {
             boolean doVibrate = (Boolean) objValue;
             Settings.System.putInt(getActivity().getContentResolver(),
@@ -161,6 +181,13 @@
      */
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+        if (!PermissionsUtil.hasAppOp(getContext(), AppOpsManager.OPSTR_WRITE_SETTINGS)) {
+            Toast.makeText(
+                    getContext(),
+                    getResources().getString(R.string.toast_cannot_write_system_settings),
+                    Toast.LENGTH_SHORT).show();
+            return true;
+        }
         if (preference == mPlayDtmfTone) {
             Settings.System.putInt(getActivity().getContentResolver(),
                     Settings.System.DTMF_TONE_WHEN_DIALING,