diff --git a/res/layout/installed_app_details.xml b/res/layout/installed_app_details.xml
index 9e1eeb5ba76..df4f7181eca 100644
--- a/res/layout/installed_app_details.xml
+++ b/res/layout/installed_app_details.xml
@@ -393,6 +393,27 @@
style="?android:attr/listSeparatorTextViewStyle"
android:layout_marginTop="8dip"
android:text="@string/permissions_label" />
+
+
+
+
+
2
- 1
+
+
+
+
+ - Ask
+
+ - Never allow
+
+ - Always allow
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f1b4a5eb64c..4df184eb98b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2559,6 +2559,10 @@
%1$s, %2$s
%1$s, %2$s
+
+ This app may charge you money:
+
+ Send premium SMS
Computing\u2026
Couldn\'t compute package size.
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 2c1944dd36a..e056f6a6a36 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -16,6 +16,8 @@
package com.android.settings.applications;
+import com.android.internal.telephony.ISms;
+import com.android.internal.telephony.SmsUsageMonitor;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry;
@@ -66,12 +68,15 @@ import java.util.List;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
import android.widget.AppSecurityPermissions;
+import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.Spinner;
import android.widget.TextView;
/**
@@ -96,6 +101,7 @@ public class InstalledAppDetails extends Fragment
private IUsbManager mUsbManager;
private AppWidgetManager mAppWidgetManager;
private DevicePolicyManager mDpm;
+ private ISms mSmsManager;
private ApplicationsState mState;
private ApplicationsState.Session mSession;
private ApplicationsState.AppEntry mAppEntry;
@@ -371,6 +377,7 @@ public class InstalledAppDetails extends Fragment
mUsbManager = IUsbManager.Stub.asInterface(b);
mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
+ mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms"));
mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
}
@@ -595,8 +602,43 @@ public class InstalledAppDetails extends Fragment
// Security permissions section
LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section);
AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), packageName);
- if (asp.getPermissionCount() > 0) {
+ int premiumSmsPermission = getPremiumSmsPermission(packageName);
+ // Premium SMS permission implies the app also has SEND_SMS permission, so the original
+ // application permissions list doesn't have to be shown/hidden separately. The premium
+ // SMS subsection should only be visible if the app has tried to send to a premium SMS.
+ if (asp.getPermissionCount() > 0
+ || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
permsView.setVisibility(View.VISIBLE);
+ } else {
+ permsView.setVisibility(View.GONE);
+ }
+ // Premium SMS permission subsection
+ TextView securityBillingDesc = (TextView) permsView.findViewById(
+ R.id.security_settings_billing_desc);
+ LinearLayout securityBillingList = (LinearLayout) permsView.findViewById(
+ R.id.security_settings_billing_list);
+ if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
+ // Show the premium SMS permission selector
+ securityBillingDesc.setVisibility(View.VISIBLE);
+ securityBillingList.setVisibility(View.VISIBLE);
+ Spinner spinner = (Spinner) permsView.findViewById(
+ R.id.security_settings_premium_sms_list);
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(getActivity(),
+ R.array.security_settings_premium_sms_values,
+ android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ // List items are in the same order as SmsUsageMonitor constants, offset by 1.
+ spinner.setSelection(premiumSmsPermission - 1);
+ spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener(
+ packageName, mSmsManager));
+ } else {
+ // Hide the premium SMS permission selector
+ securityBillingDesc.setVisibility(View.GONE);
+ securityBillingList.setVisibility(View.GONE);
+ }
+ // App permissions subsection
+ if (asp.getPermissionCount() > 0) {
// Make the security sections header visible
LinearLayout securityList = (LinearLayout) permsView.findViewById(
R.id.security_settings_list);
@@ -642,8 +684,6 @@ public class InstalledAppDetails extends Fragment
mPackageInfo.applicationInfo.loadLabel(mPm), appListStr));
}
}
- } else {
- permsView.setVisibility(View.GONE);
}
checkForceStop();
@@ -652,6 +692,42 @@ public class InstalledAppDetails extends Fragment
refreshSizeInfo();
return true;
}
+
+ private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener {
+ private final String mPackageName;
+ private final ISms mSmsManager;
+
+ PremiumSmsSelectionListener(String packageName, ISms smsManager) {
+ mPackageName = packageName;
+ mSmsManager = smsManager;
+ }
+
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position,
+ long id) {
+ if (position >= 0 && position < 3) {
+ Log.d(TAG, "Selected premium SMS policy " + position);
+ setPremiumSmsPermission(mPackageName, (position + 1));
+ } else {
+ Log.e(TAG, "Error: unknown premium SMS policy " + position);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ // Ignored
+ }
+
+ private void setPremiumSmsPermission(String packageName, int permission) {
+ try {
+ if (mSmsManager != null) {
+ mSmsManager.setPremiumSmsPermission(packageName, permission);
+ }
+ } catch (RemoteException ex) {
+ // ignored
+ }
+ }
+ }
private void resetLaunchDefaultsUi(TextView title, TextView autoLaunchView) {
title.setText(R.string.auto_launch_label);
@@ -1027,6 +1103,17 @@ public class InstalledAppDetails extends Fragment
}
}
+ private int getPremiumSmsPermission(String packageName) {
+ try {
+ if (mSmsManager != null) {
+ return mSmsManager.getPremiumSmsPermission(packageName);
+ }
+ } catch (RemoteException ex) {
+ // ignored
+ }
+ return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN;
+ }
+
/*
* Method implementing functionality of buttons clicked
* @see android.view.View.OnClickListener#onClick(android.view.View)