installedPackagesInfo) {
+ mInstalledPackageInfo = installedPackagesInfo;
+ }
+
+ public void update() {
+ reloadList();
+ }
+
+ @Override
+ public int getCount() {
+ return mInstalledPackages.size();
+ }
+
+ @Override
+ public PackageItem getItem(int position) {
+ return mInstalledPackages.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mInstalledPackages.get(position).packageName.hashCode();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+ if (convertView != null) {
+ holder = (ViewHolder) convertView.getTag();
+ } else {
+ final LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = layoutInflater.inflate(R.layout.preference_icon, null, false);
+ holder = new ViewHolder();
+ convertView.setTag(holder);
+ holder.title = (TextView) convertView.findViewById(com.android.internal.R.id.title);
+ holder.summary = (TextView) convertView
+ .findViewById(com.android.internal.R.id.summary);
+ holder.icon = (ImageView) convertView.findViewById(R.id.icon);
+ }
+ PackageItem applicationInfo = getItem(position);
+
+ if (holder.title != null) {
+ holder.title.setText(applicationInfo.title);
+ }
+ if (holder.summary != null) {
+ holder.summary.setVisibility(View.GONE);
+ }
+ if (holder.icon != null) {
+ Drawable loadIcon = applicationInfo.icon;
+ holder.icon.setImageDrawable(loadIcon);
+ holder.icon.setAdjustViewBounds(true);
+ holder.icon.setMaxHeight(72);
+ holder.icon.setMaxWidth(72);
+ }
+ return convertView;
+ }
+
+ }
+
+ static class ViewHolder {
+ TextView title;
+
+ TextView summary;
+
+ ImageView icon;
+ }
+
+}
diff --git a/src/com/android/settings/AppGroupList.java b/src/com/android/settings/AppGroupList.java
new file mode 100644
index 00000000000..809756c43f6
--- /dev/null
+++ b/src/com/android/settings/AppGroupList.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.NotificationGroup;
+import android.app.ProfileManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.widget.EditText;
+
+import java.util.UUID;
+
+public class AppGroupList extends PreferenceActivity {
+
+ private static final String TAG = "AppGroupSettings";
+
+ private ProfileManager mProfileManager;
+
+ private static final int DIALOG_NAME = 0;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.appgroup_list);
+ getListView().setItemsCanFocus(true);
+
+ setTitle(R.string.profile_appgroups_title);
+
+ mProfileManager = (ProfileManager) this.getSystemService(PROFILE_SERVICE);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ fillList();
+ }
+
+ private void addNewAppGroup() {
+ showDialog(DIALOG_NAME);
+ }
+
+ Preference mAddPreference;
+
+ private void fillList() {
+
+ mAddPreference = (PreferenceScreen) findPreference("profile_new_appgroup");
+
+ PreferenceGroup appgroupList = (PreferenceGroup) findPreference("profile_appgroup_list_title");
+ appgroupList.removeAll();
+
+ for (NotificationGroup group : mProfileManager.getNotificationGroups()) {
+
+ PreferenceScreen pref = new PreferenceScreen(this, null);
+
+ pref.setKey(group.getUuid().toString());
+ pref.setTitle(group.getName());
+ pref.setPersistent(false);
+
+ appgroupList.addPreference(pref);
+
+ }
+
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ Dialog dialog;
+ switch (id) {
+ case DIALOG_NAME:
+ final EditText entry = new EditText(this);
+ entry.setPadding(10, 10, 10, 10);
+ builder.setMessage(R.string.profile_appgroup_name_prompt);
+ builder.setView(entry);
+ builder.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ NotificationGroup newGroup = new NotificationGroup(entry.getText()
+ .toString());
+ mProfileManager.addNotificationGroup(newGroup);
+ fillList();
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ dialog = builder.create();
+ break;
+ default:
+ dialog = null;
+ }
+ return dialog;
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference instanceof PreferenceScreen) {
+ if (mAddPreference == preference) {
+ addNewAppGroup();
+ } else {
+ NotificationGroup group = mProfileManager.getNotificationGroup(
+ UUID.fromString(preference.getKey()));
+
+ editGroup(group);
+ }
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void editGroup(NotificationGroup group) {
+ Intent intent = new Intent(this, AppGroupConfig.class);
+ intent.putExtra("NotificationGroup", group);
+ startActivity(intent);
+ }
+
+}
diff --git a/src/com/android/settings/AppWidgetPickActivity.java b/src/com/android/settings/AppWidgetPickActivity.java
index cddc6875cb4..2723898c2e7 100644
--- a/src/com/android/settings/AppWidgetPickActivity.java
+++ b/src/com/android/settings/AppWidgetPickActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2010 Florian Sundermann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,79 +16,176 @@
package com.android.settings;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.DialogInterface;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
-import android.util.Log;
+import android.view.Window;
-import java.text.Collator;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
+public class AppWidgetPickActivity extends Activity {
-/**
- * Displays a list of {@link AppWidgetProviderInfo} widgets, along with any
- * injected special widgets specified through
- * {@link AppWidgetManager#EXTRA_CUSTOM_INFO} and
- * {@link AppWidgetManager#EXTRA_CUSTOM_EXTRAS}.
- *
- * When an installed {@link AppWidgetProviderInfo} is selected, this activity
- * will bind it to the given {@link AppWidgetManager#EXTRA_APPWIDGET_ID},
- * otherwise it will return the requested extras.
- */
-public class AppWidgetPickActivity extends ActivityPicker {
- private static final String TAG = "AppWidgetPickActivity";
- private static final boolean LOGD = false;
+ private Intent fIntent = null;
+ private PackageManager fPManager = null;
+ private AppWidgetManager fAppWManager = null;
+ private ArrayList fItems;
+ private int fAppWidgetId;
- private PackageManager mPackageManager;
- private AppWidgetManager mAppWidgetManager;
-
- /**
- * The allocated {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that this
- * activity is binding.
- */
- private int mAppWidgetId;
-
@Override
- public void onCreate(Bundle icicle) {
- mPackageManager = getPackageManager();
- mAppWidgetManager = AppWidgetManager.getInstance(this);
-
- super.onCreate(icicle);
-
- // Set default return data
- setResultData(RESULT_CANCELED, null);
-
- // Read the appWidgetId passed our direction, otherwise bail if not found
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.setTitle("");
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ fIntent = getIntent();
+
final Intent intent = getIntent();
if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
- mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ fAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
+ fPManager = getPackageManager();
+ fAppWManager = AppWidgetManager.getInstance(this);
+
+ fItems = new ArrayList();
+ AddAppWidgetProviderInfos();
+ AddCustomAppWidgets();
+ Collections.sort(fItems, new Comparator() {
+
+ @Override
+ public int compare(SubItem object1, SubItem object2) {
+ return object1.getName().compareToIgnoreCase(object2.getName());
+ }
+
+ });
+ for(SubItem itm : fItems) {
+ if (itm instanceof Item) {
+ ((Item)itm).sort();
+ }
+ }
+ new PickWidgetDialog(this).showDialog(null);
} else {
finish();
}
}
-
+
+ public ArrayList getItems() {
+ return fItems;
+ }
+
+
+ public void finishOk(SubItem item) {
+ int result;
+ if (item.getExtra() != null) {
+ // If there are any extras, it's because this entry is custom.
+ // Don't try to bind it, just pass it back to the app.
+ setResult(RESULT_OK, getIntent(item));
+ } else {
+ try {
+ fAppWManager.bindAppWidgetId(fAppWidgetId, item.getProvider());
+ result = RESULT_OK;
+ } catch (IllegalArgumentException e) {
+ // This is thrown if they're already bound, or otherwise somehow
+ // bogus. Set the result to canceled, and exit. The app *should*
+ // clean up at this point. We could pass the error along, but
+ // it's not clear that that's useful -- the widget will simply not
+ // appear.
+ result = RESULT_CANCELED;
+ }
+ setResult(result, fIntent);
+ }
+ finish();
+ }
+
/**
- * Create list entries for any custom widgets requested through
- * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}.
+ * Build the {@link Intent} described by this item. If this item
+ * can't create a valid {@link ComponentName}, it will return
+ * {@link Intent#ACTION_CREATE_SHORTCUT} filled with the item label.
*/
- void putCustomAppWidgets(List items) {
- final Bundle extras = getIntent().getExtras();
-
+ private Intent getIntent(SubItem itm) {
+ Intent intent = null;
+ Parcelable parcel = fIntent.getParcelableExtra(Intent.EXTRA_INTENT);
+ if (parcel instanceof Intent) {
+ intent = new Intent((Intent) parcel);
+ } else {
+ intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ }
+
+ if (itm.getProvider() != null) {
+ // Valid package and class, so fill details as normal intent
+ intent.setClassName(itm.getProvider().getPackageName(), itm.getProvider().getClassName());
+ } else {
+ // No valid package or class, so treat as shortcut with label
+ intent.setAction(Intent.ACTION_CREATE_SHORTCUT);
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, itm.getName());
+ }
+ if (itm.getExtra() != null) {
+ intent.putExtras(itm.getExtra());
+ }
+ return intent;
+ }
+
+ private Item getPackageItem(AppWidgetProviderInfo info) {
+ String packName = info.provider.getPackageName();
+ for (SubItem itm : fItems) {
+ if (itm instanceof Item) {
+ Item i = (Item)itm;
+ if (i.getPackageName().equals(packName)) {
+ return i;
+ }
+ }
+ }
+ try
+ {
+ android.content.pm.ApplicationInfo appInfo = fPManager.getApplicationInfo(info.provider.getPackageName(), 0);
+ Drawable appIcon = fPManager.getApplicationIcon(appInfo);
+ CharSequence str = fPManager.getApplicationLabel(appInfo);
+ Item newItm = new Item(str.toString(), appIcon);
+ newItm.setPackageName(packName);
+ fItems.add(newItm);
+ return newItm;
+ }
+ catch(PackageManager.NameNotFoundException expt) {
+ }
+ return null;
+ }
+
+ private void AddAppWidgetProviderInfos() {
+ List infos = fAppWManager.getInstalledProviders();
+
+ for(AppWidgetProviderInfo info : infos) {
+ try
+ {
+ android.content.pm.ApplicationInfo appInfo = fPManager.getApplicationInfo(info.provider.getPackageName(), 0);
+ SubItem itm = new SubItem(info.label, fPManager.getDrawable(info.provider.getPackageName(), info.icon, appInfo));
+ itm.setProvider(info.provider);
+ Item mainItm = getPackageItem(info);
+ mainItm.getItems().add(itm);
+ }
+ catch(PackageManager.NameNotFoundException expt) {
+ }
+ }
+ }
+
+ private void AddCustomAppWidgets() {
+ final Bundle extras = fIntent.getExtras();
+
// get and validate the extras they gave us
ArrayList customInfo = null;
ArrayList customExtras = null;
try_custom_items: {
customInfo = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_INFO);
+
if (customInfo == null || customInfo.size() == 0) {
- Log.i(TAG, "EXTRA_CUSTOM_INFO not present.");
break try_custom_items;
}
@@ -97,7 +194,6 @@ void putCustomAppWidgets(List items) {
Parcelable p = customInfo.get(i);
if (p == null || !(p instanceof AppWidgetProviderInfo)) {
customInfo = null;
- Log.e(TAG, "error using EXTRA_CUSTOM_INFO index=" + i);
break try_custom_items;
}
}
@@ -105,135 +201,48 @@ void putCustomAppWidgets(List items) {
customExtras = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_EXTRAS);
if (customExtras == null) {
customInfo = null;
- Log.e(TAG, "EXTRA_CUSTOM_INFO without EXTRA_CUSTOM_EXTRAS");
break try_custom_items;
}
-
int customExtrasSize = customExtras.size();
if (customInfoSize != customExtrasSize) {
- Log.e(TAG, "list size mismatch: EXTRA_CUSTOM_INFO: " + customInfoSize
- + " EXTRA_CUSTOM_EXTRAS: " + customExtrasSize);
break try_custom_items;
}
-
-
for (int i=0; i appWidgets,
- List customExtras, List items) {
+ private void putAppWidgetItems(List appWidgets, List customExtras) {
+ if (appWidgets == null)
+ return;
final int size = appWidgets.size();
for (int i = 0; i < size; i++) {
AppWidgetProviderInfo info = appWidgets.get(i);
-
- CharSequence label = info.label;
+
+ String label = info.label.toString();
Drawable icon = null;
if (info.icon != 0) {
- icon = mPackageManager.getDrawable(info.provider.getPackageName(), info.icon, null);
- if (icon == null) {
- Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
- + " for provider: " + info.provider);
- }
- }
-
- PickAdapter.Item item = new PickAdapter.Item(this, label, icon);
-
- item.packageName = info.provider.getPackageName();
- item.className = info.provider.getClassName();
-
- if (customExtras != null) {
- item.extras = customExtras.get(i);
+ icon = fPManager.getDrawable(info.provider.getPackageName(), info.icon, null);
}
-
- items.add(item);
- }
- }
-
- /**
- * Build and return list of items to be shown in dialog. This will mix both
- * installed {@link AppWidgetProviderInfo} and those provided through
- * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically.
- */
- @Override
- protected List getItems() {
- List items = new ArrayList();
-
- putInstalledAppWidgets(items);
- putCustomAppWidgets(items);
-
- // Sort all items together by label
- Collections.sort(items, new Comparator() {
- Collator mCollator = Collator.getInstance();
- public int compare(PickAdapter.Item lhs, PickAdapter.Item rhs) {
- return mCollator.compare(lhs.label, rhs.label);
- }
- });
- return items;
- }
+ Item item = new Item(label, icon);
+ SubItem subItem = new SubItem(label, icon);
+ item.getItems().add(subItem);
- /**
- * Create list entries for installed {@link AppWidgetProviderInfo} widgets.
- */
- void putInstalledAppWidgets(List items) {
- List installed = mAppWidgetManager.getInstalledProviders();
- putAppWidgetItems(installed, null, items);
- }
+ item.setPackageName(info.provider.getPackageName());
+ if (customExtras != null) {
+ subItem.setExtra(customExtras.get(i));
+ }
- /**
- * Convenience method for setting the result code and intent. This method
- * correctly injects the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that
- * most hosts expect returned.
- */
- void setResultData(int code, Intent intent) {
- Intent result = intent != null ? intent : new Intent();
- result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
- setResult(code, result);
+ fItems.add(item);
+ }
}
}
diff --git a/src/com/android/settings/ApplicationItemPreference.java b/src/com/android/settings/ApplicationItemPreference.java
new file mode 100644
index 00000000000..35242becfbf
--- /dev/null
+++ b/src/com/android/settings/ApplicationItemPreference.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+public class ApplicationItemPreference extends Preference {
+
+ private Drawable mIcon;
+
+ public ApplicationItemPreference(Context context) {
+ this(context, null, 0);
+ }
+
+ public ApplicationItemPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setLayoutResource(R.layout.preference_icon);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.IconPreferenceScreen, defStyle, 0);
+ mIcon = a.getDrawable(R.styleable.IconPreferenceScreen_icon);
+ }
+
+ public void setIcon(Drawable icon){
+ mIcon = icon;
+ }
+
+ @Override
+ public void onBindView(View view) {
+ super.onBindView(view);
+ ImageView imageView = (ImageView) view.findViewById(R.id.icon);
+ if (imageView != null && mIcon != null) {
+ imageView.setAdjustViewBounds(true);
+ imageView.setMaxHeight(72);
+ imageView.setMaxWidth(72);
+ imageView.setImageDrawable(mIcon);
+ }
+ }
+}
diff --git a/src/com/android/settings/ApplicationSettings.java b/src/com/android/settings/ApplicationSettings.java
index 6a8aa81128d..a919ae84929 100644
--- a/src/com/android/settings/ApplicationSettings.java
+++ b/src/com/android/settings/ApplicationSettings.java
@@ -21,21 +21,35 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
public class ApplicationSettings extends PreferenceActivity implements
DialogInterface.OnClickListener {
private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
+ private static final String KEY_APP_INSTALL_LOCATION = "app_install_location";
private static final String KEY_QUICK_LAUNCH = "quick_launch";
- private CheckBoxPreference mToggleAppInstallation;
+ // App installation location. Default is ask the user.
+ private static final int APP_INSTALL_AUTO = 0;
+ private static final int APP_INSTALL_DEVICE = 1;
+ private static final int APP_INSTALL_SDCARD = 2;
- private DialogInterface mWarnInstallApps;
+ private static final String APP_INSTALL_DEVICE_ID = "device";
+ private static final String APP_INSTALL_SDCARD_ID = "sdcard";
+ private static final String APP_INSTALL_AUTO_ID = "auto";
+ private CheckBoxPreference mToggleAppInstallation;
+
+ private ListPreference mInstallLocation;
+
+ private DialogInterface mWarnInstallApps;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -45,6 +59,23 @@ protected void onCreate(Bundle icicle) {
mToggleAppInstallation = (CheckBoxPreference) findPreference(KEY_TOGGLE_INSTALL_APPLICATIONS);
mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
+ mInstallLocation = (ListPreference) findPreference(KEY_APP_INSTALL_LOCATION);
+ // Is app default install location set?
+ boolean userSetInstLocation = (Settings.System.getInt(getContentResolver(),
+ Settings.Secure.SET_INSTALL_LOCATION, 0) != 0);
+ if (!userSetInstLocation) {
+ getPreferenceScreen().removePreference(mInstallLocation);
+ } else {
+ mInstallLocation.setValue(getAppInstallLocation());
+ mInstallLocation.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String value = (String) newValue;
+ handleUpdateAppInstallLocation(value);
+ return false;
+ }
+ });
+ }
+
if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
// No hard keyboard, remove the setting for quick launch
Preference quickLaunchSetting = findPreference(KEY_QUICK_LAUNCH);
@@ -52,6 +83,24 @@ protected void onCreate(Bundle icicle) {
}
}
+ protected void handleUpdateAppInstallLocation(final String value) {
+ if(APP_INSTALL_DEVICE_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_DEVICE);
+ } else if (APP_INSTALL_SDCARD_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_SDCARD);
+ } else if (APP_INSTALL_AUTO_ID.equals(value)) {
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ } else {
+ // Should not happen, default to prompt...
+ Settings.System.putInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ }
+ mInstallLocation.setValue(value);
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -70,12 +119,12 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
setNonMarketAppsAllowed(false);
}
}
-
+
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
public void onClick(DialogInterface dialog, int which) {
- if (dialog == mWarnInstallApps && which == DialogInterface.BUTTON1) {
+ if (dialog == mWarnInstallApps && which == DialogInterface.BUTTON_POSITIVE) {
setNonMarketAppsAllowed(true);
mToggleAppInstallation.setChecked(true);
}
@@ -92,6 +141,21 @@ private boolean isNonMarketAppsAllowed() {
Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
}
+ private String getAppInstallLocation() {
+ int selectedLocation = Settings.System.getInt(getContentResolver(),
+ Settings.Secure.DEFAULT_INSTALL_LOCATION, APP_INSTALL_AUTO);
+ if (selectedLocation == APP_INSTALL_DEVICE) {
+ return APP_INSTALL_DEVICE_ID;
+ } else if (selectedLocation == APP_INSTALL_SDCARD) {
+ return APP_INSTALL_SDCARD_ID;
+ } else if (selectedLocation == APP_INSTALL_AUTO) {
+ return APP_INSTALL_AUTO_ID;
+ } else {
+ // Default value, should not happen.
+ return APP_INSTALL_AUTO_ID;
+ }
+ }
+
private void warnAppInstallation() {
mWarnInstallApps = new AlertDialog.Builder(this)
.setTitle(getString(R.string.error_title))
@@ -101,6 +165,4 @@ private void warnAppInstallation() {
.setNegativeButton(android.R.string.no, null)
.show();
}
-
-
}
diff --git a/src/com/android/settings/BandMode.java b/src/com/android/settings/BandMode.java
index 1297cad5d6d..4c7663ede70 100644
--- a/src/com/android/settings/BandMode.java
+++ b/src/com/android/settings/BandMode.java
@@ -62,7 +62,7 @@ protected void onCreate(Bundle icicle) {
setContentView(R.layout.band_mode);
setTitle(getString(R.string.band_mode_title));
- getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT,
+ getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
mPhone = PhoneFactory.getDefaultPhone();
@@ -97,7 +97,7 @@ public void onItemClick(AdapterView parent, View v,
}
};
- private class BandListItem {
+ static private class BandListItem {
private int mBandMode = Phone.BM_UNSPECIFIED;
public BandListItem(int bm) {
diff --git a/src/com/android/settings/BatteryInfo.java b/src/com/android/settings/BatteryInfo.java
index eb7ddb49f1b..1cbe47f988a 100644
--- a/src/com/android/settings/BatteryInfo.java
+++ b/src/com/android/settings/BatteryInfo.java
@@ -36,6 +36,7 @@
public class BatteryInfo extends Activity {
private TextView mStatus;
+ private TextView mPower;
private TextView mLevel;
private TextView mScale;
private TextView mHealth;
@@ -67,7 +68,7 @@ public void handleMessage(Message msg) {
*/
private final String tenthsToFixedString(int x) {
int tens = x / 10;
- return new String("" + tens + "." + (x - 10*tens));
+ return Integer.toString(tens) + "." + (x - 10 * tens);
}
/**
@@ -111,6 +112,24 @@ public void onReceive(Context context, Intent intent) {
}
mStatus.setText(statusString);
+ switch (plugType) {
+ case 0:
+ mPower.setText(getString(R.string.battery_info_power_unplugged));
+ break;
+ case BatteryManager.BATTERY_PLUGGED_AC:
+ mPower.setText(getString(R.string.battery_info_power_ac));
+ break;
+ case BatteryManager.BATTERY_PLUGGED_USB:
+ mPower.setText(getString(R.string.battery_info_power_usb));
+ break;
+ case (BatteryManager.BATTERY_PLUGGED_AC|BatteryManager.BATTERY_PLUGGED_USB):
+ mPower.setText(getString(R.string.battery_info_power_ac_usb));
+ break;
+ default:
+ mPower.setText(getString(R.string.battery_info_power_unknown));
+ break;
+ }
+
int health = intent.getIntExtra("health", BatteryManager.BATTERY_HEALTH_UNKNOWN);
String healthString;
if (health == BatteryManager.BATTERY_HEALTH_GOOD) {
@@ -148,6 +167,7 @@ public void onResume() {
super.onResume();
mStatus = (TextView)findViewById(R.id.status);
+ mPower = (TextView)findViewById(R.id.power);
mLevel = (TextView)findViewById(R.id.level);
mScale = (TextView)findViewById(R.id.scale);
mHealth = (TextView)findViewById(R.id.health);
diff --git a/src/com/android/settings/BrightnessPreference.java b/src/com/android/settings/BrightnessPreference.java
index 9f554632631..7494e2fc23c 100644
--- a/src/com/android/settings/BrightnessPreference.java
+++ b/src/com/android/settings/BrightnessPreference.java
@@ -18,7 +18,7 @@
import android.content.Context;
import android.os.RemoteException;
-import android.os.IHardwareService;
+import android.os.IPowerManager;
import android.os.ServiceManager;
import android.preference.SeekBarPreference;
import android.provider.Settings;
@@ -26,16 +26,22 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.SeekBar;
import java.util.Map;
public class BrightnessPreference extends SeekBarPreference implements
- SeekBar.OnSeekBarChangeListener {
+ SeekBar.OnSeekBarChangeListener, CheckBox.OnCheckedChangeListener {
private SeekBar mSeekBar;
+ private CheckBox mCheckBox;
private int mOldBrightness;
+ private int mOldAutomatic;
+
+ private boolean mAutomaticAvailable;
// Backlight range is from 0 - 255. Need to make sure that user
// doesn't set the backlight to 0 and get stuck
@@ -44,6 +50,12 @@ public class BrightnessPreference extends SeekBarPreference implements
public BrightnessPreference(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ mAutomaticAvailable = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_automatic_brightness_available);
+
+ setDialogLayoutResource(R.layout.preference_dialog_brightness);
+ setDialogIcon(R.drawable.ic_settings_display);
}
@Override
@@ -51,7 +63,6 @@ protected void onBindDialogView(View view) {
super.onBindDialogView(view);
mSeekBar = getSeekBar(view);
- mSeekBar.setOnSeekBarChangeListener(this);
mSeekBar.setMax(MAXIMUM_BACKLIGHT - MINIMUM_BACKLIGHT);
try {
mOldBrightness = Settings.System.getInt(getContext().getContentResolver(),
@@ -60,6 +71,21 @@ protected void onBindDialogView(View view) {
mOldBrightness = MAXIMUM_BACKLIGHT;
}
mSeekBar.setProgress(mOldBrightness - MINIMUM_BACKLIGHT);
+
+ mCheckBox = (CheckBox)view.findViewById(R.id.automatic_mode);
+ if (mAutomaticAvailable) {
+ mCheckBox.setOnCheckedChangeListener(this);
+ try {
+ mOldAutomatic = Settings.System.getInt(getContext().getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE);
+ } catch (SettingNotFoundException snfe) {
+ mOldAutomatic = 0;
+ }
+ mCheckBox.setChecked(mOldAutomatic != 0);
+ } else {
+ mCheckBox.setVisibility(View.GONE);
+ }
+ mSeekBar.setOnSeekBarChangeListener(this);
}
public void onProgressChanged(SeekBar seekBar, int progress,
@@ -75,6 +101,14 @@ public void onStopTrackingTouch(SeekBar seekBar) {
// NA
}
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ setMode(isChecked ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
+ : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+ if (!isChecked) {
+ setBrightness(mSeekBar.getProgress() + MINIMUM_BACKLIGHT);
+ }
+ }
+
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
@@ -84,20 +118,35 @@ protected void onDialogClosed(boolean positiveResult) {
Settings.System.SCREEN_BRIGHTNESS,
mSeekBar.getProgress() + MINIMUM_BACKLIGHT);
} else {
- setBrightness(mOldBrightness);
+ if (mAutomaticAvailable) {
+ setMode(mOldAutomatic);
+ }
+ if (!mAutomaticAvailable || mOldAutomatic == 0) {
+ setBrightness(mOldBrightness);
+ }
}
}
private void setBrightness(int brightness) {
try {
- IHardwareService hardware = IHardwareService.Stub.asInterface(
- ServiceManager.getService("hardware"));
- if (hardware != null) {
- hardware.setBacklights(brightness);
+ IPowerManager power = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));
+ if (power != null) {
+ power.setBacklightBrightness(brightness);
}
} catch (RemoteException doe) {
}
}
+
+ private void setMode(int mode) {
+ if (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
+ mSeekBar.setVisibility(View.GONE);
+ } else {
+ mSeekBar.setVisibility(View.VISIBLE);
+ }
+ Settings.System.putInt(getContext().getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE, mode);
+ }
}
diff --git a/src/com/android/settings/ChooseLockFinger.java b/src/com/android/settings/ChooseLockFinger.java
new file mode 100644
index 00000000000..dc90873b57c
--- /dev/null
+++ b/src/com/android/settings/ChooseLockFinger.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import dalvik.system.DexClassLoader;
+
+import java.util.concurrent.Semaphore;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
+import android.content.Context;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+
+import com.authentec.AuthentecHelper;
+
+public class ChooseLockFinger extends PreferenceActivity {
+
+ private static final String KEY_TOGGLE_UNLOCK_FINGER = "toggle_unlock_finger";
+ private static final String KEY_START_ENROLLMENT_WIZARD = "start_enrollment_wizard";
+
+ // result of an operation from a remote intent
+ private int miResult;
+ private LockPatternUtils mLockPatternUtils;
+ private ChooseLockFinger mChooseLockFinger;
+
+ private CheckBoxPreference mToggleUnlockFinger;
+ private Preference mStartEnrollmentWizard;
+ private boolean mbFingerSetting = false;
+ private String msTempPasscode = null;
+
+ private AuthentecHelper fingerhelper;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Always initialize the pointer to NULL at the begining.
+ msTempPasscode = null;
+
+ // use the intent's bundle and parameters in it to determine how it was started.
+ Bundle bundle = getIntent().getExtras();
+ if (bundle != null) {
+ msTempPasscode = bundle.getString("temp-passcode");
+ }
+
+ // Don't show the tutorial if the user has seen it before.
+ mLockPatternUtils = new LockPatternUtils(this);
+ mChooseLockFinger = this;
+
+ // Load TSM
+ fingerhelper = AuthentecHelper.getInstance(this);
+
+ if (mLockPatternUtils.savedFingerExists()) {
+ // Previous enrolled fingers exist.
+ mbFingerSetting = true;
+
+ addPreferencesFromResource(R.xml.finger_prefs);
+ mToggleUnlockFinger = (CheckBoxPreference) findPreference(KEY_TOGGLE_UNLOCK_FINGER);
+ if (mLockPatternUtils.isLockFingerEnabled()) {
+ mToggleUnlockFinger.setChecked(true);
+ } else {
+ mToggleUnlockFinger.setChecked(false);
+ }
+ mStartEnrollmentWizard = (Preference) findPreference(KEY_START_ENROLLMENT_WIZARD);
+ mStartEnrollmentWizard.setTitle(R.string.lockfinger_change_finger_unlock_title);
+ } else {
+ mbFingerSetting = false;
+ startEnrollmentWizard();
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference == mToggleUnlockFinger) {
+ if (mToggleUnlockFinger.isChecked()) {
+ startVerification();
+ } else {
+ // Turn off the unlock finger mode.
+ mLockPatternUtils.setLockFingerEnabled(false);
+ mToggleUnlockFinger.setChecked(false);
+ // Destroy the activity.
+ mChooseLockFinger.finish();
+ }
+ } else if (preference == mStartEnrollmentWizard) {
+ startEnrollmentWizard();
+ }
+
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ // The toast() function is provided to allow non-UI thread code to
+ // conveniently raise a toast...
+ private void toast(final String s)
+ {
+ runOnUiThread(new Runnable() {
+ public void run()
+ {
+ Toast.makeText(mChooseLockFinger, s, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ private void startEnrollmentWizard()
+ {
+ // launch a thread for the enrollment wizard
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+
+ int miResult = fingerhelper.startEnrollmentWizard(ChooseLockFinger.this, msTempPasscode);
+
+ // process the returned result
+ switch (miResult) {
+ case AuthentecHelper.eAM_STATUS_OK:
+ toast(getString(R.string.lockfinger_enrollment_succeeded_toast));
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mLockPatternUtils.setLockFingerEnabled(true);
+ if (mbFingerSetting) {
+ mToggleUnlockFinger.setEnabled(true);
+ mToggleUnlockFinger.setChecked(true);
+ mStartEnrollmentWizard.setTitle(R.string.lockfinger_change_finger_unlock_title);
+ }
+ }
+ });
+ break;
+
+ case AuthentecHelper.eAM_STATUS_LIBRARY_NOT_AVAILABLE:
+ toast(getString(R.string.lockfinger_tsm_library_not_available_toast));
+ break;
+
+ case AuthentecHelper.eAM_STATUS_USER_CANCELED:
+ toast(getString(R.string.lockfinger_enrollment_canceled_toast));
+ break;
+
+ case AuthentecHelper.eAM_STATUS_TIMEOUT:
+ toast(getString(R.string.lockfinger_enrollment_timeout_toast));
+ break;
+
+ case AuthentecHelper.eAM_STATUS_UNKNOWN_ERROR:
+ toast(getString(R.string.lockfinger_enrollment_unknown_error_toast));
+ break;
+
+ case AuthentecHelper.eAM_STATUS_DATABASE_FULL:
+ toast(getString(R.string.lockfinger_enrollment_database_full));
+ break;
+
+ default:
+ toast(getString(R.string.lockfinger_enrollment_failure_default_toast, miResult));
+ }
+ } catch (Exception e) {e.printStackTrace();}
+
+ // Destroy the activity.
+ mChooseLockFinger.finish();
+ }
+ }).start();
+ }
+
+ private void startVerification()
+ {
+ // launch a thread for the verification
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ int miResult = fingerhelper.startVerification(ChooseLockFinger.this);
+
+ // process the returned result
+ if (miResult == AuthentecHelper.eAM_STATUS_OK) {
+ // Turn on the fingerprint unlock mode with the previously enrolled finger(s).
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mLockPatternUtils.setLockFingerEnabled(true);
+ mToggleUnlockFinger.setChecked(true);
+ }
+ });
+ } else {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mToggleUnlockFinger.setChecked(false);
+ }
+ });
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // Destroy the activity.
+ mChooseLockFinger.finish();
+ }
+ }).start();
+ }
+}
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
new file mode 100644
index 00000000000..521e2aa516f
--- /dev/null
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceScreen;
+import android.view.View;
+
+public class ChooseLockGeneric extends PreferenceActivity {
+ private static final int MIN_PASSWORD_LENGTH = 4;
+ private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
+ private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
+ private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
+ private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
+ private static final String KEY_UNLOCK_SET_FINGER = "unlock_set_finger";
+ private static final int CONFIRM_EXISTING_REQUEST = 100;
+ private static final String PASSWORD_CONFIRMED = "password_confirmed";
+ private static final String CONFIRM_CREDENTIALS = "confirm_credentials";
+
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private DevicePolicyManager mDPM;
+ private boolean mPasswordConfirmed = false;
+ private String msTempPasscode = null;
+ private View mFingerprint;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
+
+ if (savedInstanceState != null) {
+ mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
+ }
+
+ if (!mPasswordConfirmed) {
+ ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this);
+ if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) {
+ mPasswordConfirmed = true; // no password set, so no need to confirm
+ updatePreferencesOrFinish();
+ }
+ } else {
+ updatePreferencesOrFinish();
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+ Preference preference) {
+ final String key = preference.getKey();
+ boolean handled = true;
+ if (KEY_UNLOCK_SET_NONE.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ } else if (KEY_UNLOCK_SET_FINGER.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_FINGER);
+ } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
+ } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
+ updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
+ } else {
+ handled = false;
+ }
+ return handled;
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == RESULT_OK) {
+ mPasswordConfirmed = true;
+ if (data != null) {
+ // Get the returned temporary passcode for FP unlock mode
+ Bundle bundle = data.getExtras();
+ if (bundle != null) {
+ msTempPasscode = bundle.getString("temp-passcode");
+ }
+ }
+ updatePreferencesOrFinish();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ // Saved so we don't force user to re-enter their password if configuration changes
+ outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
+ }
+
+ private void updatePreferencesOrFinish() {
+ int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
+ if (quality == -1) {
+ // If caller didn't specify password quality, show the UI and allow the user to choose.
+ quality = mChooseLockSettingsHelper.utils().getKeyguardStoredPasswordQuality();
+ final PreferenceScreen prefScreen = getPreferenceScreen();
+ if (prefScreen != null) {
+ prefScreen.removeAll();
+ }
+ addPreferencesFromResource(R.xml.security_settings_picker);
+ disableUnusablePreferences(mDPM.getPasswordQuality(null));
+ } else {
+ updateUnlockMethodAndFinish(quality);
+ }
+ }
+
+ /***
+ * Disables preferences that are less secure than required quality.
+ *
+ * @param quality the requested quality.
+ */
+ private void disableUnusablePreferences(final int quality) {
+ final Preference picker = getPreferenceScreen().findPreference("security_picker_category");
+ final PreferenceCategory cat = (PreferenceCategory) picker;
+ final int preferenceCount = cat.getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ Preference pref = cat.getPreference(i);
+ if (pref instanceof PreferenceScreen) {
+ final String key = ((PreferenceScreen) pref).getKey();
+ boolean enabled = true;
+ if (KEY_UNLOCK_SET_NONE.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+ } else if (KEY_UNLOCK_SET_FINGER.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_FINGER;
+ } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+ } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
+ enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+ }
+ if (!enabled) {
+ pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
+ pref.setEnabled(false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Invokes an activity to change the user's pattern, password or PIN based on given quality
+ * and minimum quality specified by DevicePolicyManager. If quality is
+ * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
+ *
+ * @param quality the desired quality. Ignored if DevicePolicyManager requires more security.
+ */
+ void updateUnlockMethodAndFinish(int quality) {
+ // Sanity check. We should never get here without confirming user's existing password first.
+ if (!mPasswordConfirmed) {
+ throw new IllegalStateException("Tried to update password without confirming first");
+ }
+
+ // Compare minimum allowed password quality and launch appropriate security setting method
+ int minQuality = mDPM.getPasswordQuality(null);
+ if (quality < minQuality) {
+ quality = minQuality;
+ }
+ if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
+ int minLength = mDPM.getPasswordMinimumLength(null);
+ if (minLength < MIN_PASSWORD_LENGTH) {
+ minLength = MIN_PASSWORD_LENGTH;
+ }
+ final int maxLength = mDPM.getPasswordMaximumLength(quality);
+ Intent intent = new Intent().setClass(this, ChooseLockPassword.class);
+ intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality);
+ intent.putExtra(ChooseLockPassword.PASSWORD_MIN_KEY, minLength);
+ intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength);
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_FINGER) {
+ Intent intent = new Intent().setClass(this, ChooseLockFinger.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ //intent.putExtra("key_lock_method", "finger");
+ if (msTempPasscode != null) {
+ // Transmit the temporary passcode to ChooseLockFinger
+ intent.putExtra("temp-passcode", msTempPasscode);
+ // Clear the temporary passcode string
+ msTempPasscode = null;
+ }
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ startActivity(intent);
+ } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
+ boolean showTutorial = !mChooseLockSettingsHelper.utils().isPatternEverChosen();
+ Intent intent = new Intent();
+ intent.setClass(this, showTutorial
+ ? ChooseLockPatternTutorial.class
+ : ChooseLockPattern.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ intent.putExtra("key_lock_method", "pattern");
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ startActivity(intent);
+ } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ mChooseLockSettingsHelper.utils().clearLock();
+ setResult(RESULT_OK);
+ }
+ finish();
+ }
+}
diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java
new file mode 100644
index 00000000000..b5e72d7f720
--- /dev/null
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.PasswordEntryKeyboardHelper;
+import com.android.internal.widget.PasswordEntryKeyboardView;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+import android.inputmethodservice.KeyboardView;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+
+public class ChooseLockPassword extends Activity implements OnClickListener, OnEditorActionListener,
+ TextWatcher {
+ private static final String KEY_FIRST_PIN = "first_pin";
+ private static final String KEY_UI_STAGE = "ui_stage";
+ private TextView mPasswordEntry;
+ private int mPasswordMinLength = 4;
+ private int mPasswordMaxLength = 16;
+ private LockPatternUtils mLockPatternUtils;
+ private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private com.android.settings.ChooseLockPassword.Stage mUiStage = Stage.Introduction;
+ private TextView mHeaderText;
+ private String mFirstPin;
+ private KeyboardView mKeyboardView;
+ private PasswordEntryKeyboardHelper mKeyboardHelper;
+ private boolean mIsAlphaMode;
+ private Button mCancelButton;
+ private Button mNextButton;
+ public static final String PASSWORD_MIN_KEY = "lockscreen.password_min";
+ public static final String PASSWORD_MAX_KEY = "lockscreen.password_max";
+ private static Handler mHandler = new Handler();
+ private static final int CONFIRM_EXISTING_REQUEST = 58;
+ static final int RESULT_FINISHED = RESULT_FIRST_USER;
+ private static final long ERROR_MESSAGE_TIMEOUT = 3000;
+
+ /**
+ * Keep track internally of where the user is in choosing a pattern.
+ */
+ protected enum Stage {
+
+ Introduction(R.string.lockpassword_choose_your_password_header,
+ R.string.lockpassword_choose_your_pin_header,
+ R.string.lockpassword_continue_label),
+
+ NeedToConfirm(R.string.lockpassword_confirm_your_password_header,
+ R.string.lockpassword_confirm_your_pin_header,
+ R.string.lockpassword_ok_label),
+
+ ConfirmWrong(R.string.lockpassword_confirm_passwords_dont_match,
+ R.string.lockpassword_confirm_pins_dont_match,
+ R.string.lockpassword_continue_label);
+
+ /**
+ * @param headerMessage The message displayed at the top.
+ */
+ Stage(int hintInAlpha, int hintInNumeric, int nextButtonText) {
+ this.alphaHint = hintInAlpha;
+ this.numericHint = hintInNumeric;
+ this.buttonText = nextButtonText;
+ }
+
+ public final int alphaHint;
+ public final int numericHint;
+ public final int buttonText;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(this);
+ mRequestedQuality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality);
+ mPasswordMinLength = getIntent().getIntExtra(PASSWORD_MIN_KEY, mPasswordMinLength);
+ mPasswordMaxLength = getIntent().getIntExtra(PASSWORD_MAX_KEY, mPasswordMaxLength);
+
+ final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
+ int minMode = mLockPatternUtils.getRequestedPasswordQuality();
+ if (mRequestedQuality < minMode) {
+ mRequestedQuality = minMode;
+ }
+ int minLength = mLockPatternUtils.getRequestedMinimumPasswordLength();
+ if (mPasswordMinLength < minLength) {
+ mPasswordMinLength = minLength;
+ }
+ initViews();
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
+ if (savedInstanceState == null) {
+ updateStage(Stage.Introduction);
+ if (confirmCredentials) {
+ mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
+ null, null);
+ }
+ }
+ }
+
+ private void initViews() {
+ setContentView(R.layout.choose_lock_password);
+ // Disable IME on our window since we provide our own keyboard
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+ mCancelButton = (Button) findViewById(R.id.cancel_button);
+ mCancelButton.setOnClickListener(this);
+ mNextButton = (Button) findViewById(R.id.next_button);
+ mNextButton.setOnClickListener(this);
+
+ mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
+ mPasswordEntry = (TextView) findViewById(R.id.password_entry);
+ mPasswordEntry.setOnEditorActionListener(this);
+ mPasswordEntry.addTextChangedListener(this);
+
+ mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
+ || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == mRequestedQuality;
+ mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
+ mKeyboardHelper.setKeyboardMode(mIsAlphaMode ?
+ PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
+ : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
+
+ mHeaderText = (TextView) findViewById(R.id.headerText);
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateStage(mUiStage);
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(KEY_UI_STAGE, mUiStage.name());
+ outState.putString(KEY_FIRST_PIN, mFirstPin);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ String state = savedInstanceState.getString(KEY_UI_STAGE);
+ mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
+ if (state != null) {
+ mUiStage = Stage.valueOf(state);
+ updateStage(mUiStage);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ setResult(RESULT_FINISHED);
+ finish();
+ }
+ break;
+ }
+ }
+
+ protected void updateStage(Stage stage) {
+ mUiStage = stage;
+ updateUi();
+ }
+
+ /**
+ * Validates PIN and returns a message to display if PIN fails test.
+ * @param password the raw password the user typed in
+ * @return error message to show to user or null if password is OK
+ */
+ private String validatePassword(String password) {
+ if (password.length() < mPasswordMinLength) {
+ return getString(mIsAlphaMode ?
+ R.string.lockpassword_password_too_short
+ : R.string.lockpassword_pin_too_short, mPasswordMinLength);
+ }
+ if (password.length() > mPasswordMaxLength) {
+ return getString(mIsAlphaMode ?
+ R.string.lockpassword_password_too_long
+ : R.string.lockpassword_pin_too_long, mPasswordMaxLength);
+ }
+ boolean hasAlpha = false;
+ boolean hasDigit = false;
+ boolean hasSymbol = false;
+ for (int i = 0; i < password.length(); i++) {
+ char c = password.charAt(i);
+ // allow non white space Latin-1 characters only
+ if (c <= 32 || c > 127) {
+ return getString(R.string.lockpassword_illegal_character);
+ }
+ if (c >= '0' && c <= '9') {
+ hasDigit = true;
+ } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ hasAlpha = true;
+ } else {
+ hasSymbol = true;
+ }
+ }
+ if (DevicePolicyManager.PASSWORD_QUALITY_NUMERIC == mRequestedQuality
+ && (hasAlpha | hasSymbol)) {
+ // This shouldn't be possible unless user finds some way to bring up soft keyboard
+ return getString(R.string.lockpassword_pin_contains_non_digits);
+ } else {
+ final boolean alphabetic = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
+ == mRequestedQuality;
+ final boolean alphanumeric = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
+ == mRequestedQuality;
+ final boolean symbolic = false; // not yet
+ if ((alphabetic || alphanumeric) && !hasAlpha) {
+ return getString(R.string.lockpassword_password_requires_alpha);
+ }
+ if (alphanumeric && !hasDigit) {
+ return getString(R.string.lockpassword_password_requires_digit);
+ }
+ if (symbolic && !hasSymbol) {
+ return getString(R.string.lockpassword_password_requires_symbol);
+ }
+ }
+ return null;
+ }
+
+ private void handleNext() {
+ final String pin = mPasswordEntry.getText().toString();
+ if (TextUtils.isEmpty(pin)) {
+ return;
+ }
+ String errorMsg = null;
+ if (mUiStage == Stage.Introduction) {
+ errorMsg = validatePassword(pin);
+ if (errorMsg == null) {
+ mFirstPin = pin;
+ updateStage(Stage.NeedToConfirm);
+ mPasswordEntry.setText("");
+ }
+ } else if (mUiStage == Stage.NeedToConfirm) {
+ if (mFirstPin.equals(pin)) {
+ mLockPatternUtils.clearLock();
+ mLockPatternUtils.saveLockPassword(pin, mRequestedQuality);
+ finish();
+ } else {
+ updateStage(Stage.ConfirmWrong);
+ CharSequence tmp = mPasswordEntry.getText();
+ if (tmp != null) {
+ Selection.setSelection((Spannable) tmp, 0, tmp.length());
+ }
+ }
+ }
+ if (errorMsg != null) {
+ showError(errorMsg, mUiStage);
+ }
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.next_button:
+ handleNext();
+ break;
+
+ case R.id.cancel_button:
+ finish();
+ break;
+ }
+ }
+
+ private void showError(String msg, final Stage next) {
+ mHeaderText.setText(msg);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ updateStage(next);
+ }
+ }, ERROR_MESSAGE_TIMEOUT);
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Check if this was the result of hitting the enter key
+ if (actionId == EditorInfo.IME_NULL) {
+ handleNext();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Update the hint based on current Stage and length of password entry
+ */
+ private void updateUi() {
+ String password = mPasswordEntry.getText().toString();
+ final int length = password.length();
+ if (mUiStage == Stage.Introduction && length > 0) {
+ if (length < mPasswordMinLength) {
+ String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
+ : R.string.lockpassword_pin_too_short, mPasswordMinLength);
+ mHeaderText.setText(msg);
+ mNextButton.setEnabled(false);
+ } else {
+ String error = validatePassword(password);
+ if (error != null) {
+ mHeaderText.setText(error);
+ mNextButton.setEnabled(false);
+ } else {
+ mHeaderText.setText(R.string.lockpassword_press_continue);
+ mNextButton.setEnabled(true);
+ }
+ }
+ } else {
+ mHeaderText.setText(mIsAlphaMode ? mUiStage.alphaHint : mUiStage.numericHint);
+ mNextButton.setEnabled(length > 0);
+ }
+ mNextButton.setText(mUiStage.buttonText);
+ }
+
+ public void afterTextChanged(Editable s) {
+ // Changing the text while error displayed resets to NeedToConfirm state
+ if (mUiStage == Stage.ConfirmWrong) {
+ mUiStage = Stage.NeedToConfirm;
+ }
+ updateUi();
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+}
diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java
index d0c375844ae..b3203fb4f4f 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -21,11 +21,13 @@
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
+import com.android.internal.widget.LockPatternView.Cell;
import static com.android.internal.widget.LockPatternView.DisplayMode;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import android.provider.Settings;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
@@ -44,7 +46,6 @@
* - saves chosen password when confirmed
*/
public class ChooseLockPattern extends Activity implements View.OnClickListener{
-
/**
* Used by the choose lock pattern wizard to indicate the wizard is
* finished, and each activity in the wizard should finish.
@@ -55,7 +56,9 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
* result.
*/
static final int RESULT_FINISHED = RESULT_FIRST_USER;
-
+
+ public static final int CONFIRM_EXISTING_REQUEST = 55;
+
// how long after a confirmation message is shown before moving on
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
@@ -64,29 +67,38 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{
private static final int ID_EMPTY_MESSAGE = -1;
-
protected TextView mHeaderText;
protected LockPatternView mLockPatternView;
protected TextView mFooterText;
private TextView mFooterLeftButton;
private TextView mFooterRightButton;
-
protected List mChosenPattern = null;
- protected LockPatternUtils mLockPatternUtils;
-
/**
* The patten used during the help screen to show how to draw a pattern.
*/
private final List mAnimatePattern =
- Collections.unmodifiableList(
- Lists.newArrayList(
- LockPatternView.Cell.of(0, 0),
- LockPatternView.Cell.of(0, 1),
- LockPatternView.Cell.of(1, 1),
- LockPatternView.Cell.of(2, 1)
- ));
+ Collections.unmodifiableList(Lists.newArrayList(
+ LockPatternView.Cell.of(0, 0),
+ LockPatternView.Cell.of(0, 1),
+ LockPatternView.Cell.of(1, 1),
+ LockPatternView.Cell.of(2, 1)
+ ));
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case CONFIRM_EXISTING_REQUEST:
+ if (resultCode != Activity.RESULT_OK) {
+ setResult(RESULT_FINISHED);
+ finish();
+ }
+ updateStage(Stage.Introduction);
+ break;
+ }
+ }
/**
* The pattern listener that responds according to a user choosing a new
@@ -124,6 +136,10 @@ public void onPatternDetected(List pattern) {
}
}
+ public void onPatternCellAdded(List pattern) {
+
+ }
+
private void patternInProgress() {
mHeaderText.setText(R.string.lockpattern_recording_inprogress);
mFooterText.setText("");
@@ -245,19 +261,19 @@ public void run() {
}
};
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+
private static final String KEY_UI_STAGE = "uiStage";
private static final String KEY_PATTERN_CHOICE = "chosenPattern";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
-
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setupViews();
-
+
// make it so unhandled touch events within the unlock screen go to the
// lock pattern view.
final LinearLayoutWithDefaultTouchRecepient topLayout
@@ -265,12 +281,22 @@ protected void onCreate(Bundle savedInstanceState) {
R.id.topLayout);
topLayout.setDefaultTouchRecepient(mLockPatternView);
+ final boolean confirmCredentials = getIntent().getBooleanExtra("confirm_credentials", true);
+
if (savedInstanceState == null) {
- // first launch
- updateStage(Stage.Introduction);
- if (mLockPatternUtils.savedPatternExists()) {
- confirmPattern();
- }
+ if (confirmCredentials) {
+ // first launch. As a security measure, we're in NeedToConfirm mode until we know
+ // there isn't an existing password or the user confirms their password.
+ updateStage(Stage.NeedToConfirm);
+ boolean launchedConfirmationActivity =
+ mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
+ null, null);
+ if (!launchedConfirmationActivity) {
+ updateStage(Stage.Introduction);
+ }
+ } else {
+ updateStage(Stage.Introduction);
+ }
} else {
// restore from previous state
final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);
@@ -280,19 +306,20 @@ protected void onCreate(Bundle savedInstanceState) {
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
}
}
-
+
/**
* Keep all "find view" related stuff confined to this function since in
* case someone needs to subclass and customize.
*/
protected void setupViews() {
setContentView(R.layout.choose_lock_pattern);
-
+
mHeaderText = (TextView) findViewById(R.id.headerText);
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
- mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+ mLockPatternView.setTactileFeedbackEnabled(
+ mChooseLockSettingsHelper.utils().isTactileFeedbackEnabled());
mFooterText = (TextView) findViewById(R.id.footerText);
@@ -359,35 +386,6 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
- /**
- * Launch screen to confirm the existing lock pattern.
- * @see #onActivityResult(int, int, android.content.Intent)
- */
- protected void confirmPattern() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
- startActivityForResult(intent, 55);
- }
-
- /**
- * @see #confirmPattern
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode != 55) {
- return;
- }
-
- if (resultCode != Activity.RESULT_OK) {
- setResult(RESULT_FINISHED);
- finish();
- }
- updateStage(Stage.Introduction);
- }
-
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -409,7 +407,7 @@ protected void updateStage(Stage stage) {
mUiStage = stage;
- // header text, footer text, visibility and
+ // header text, footer text, visibility and
// enabled state all known from the stage
if (stage == Stage.ChoiceTooShort) {
mHeaderText.setText(
@@ -481,16 +479,24 @@ private void postClearPatternRunnable() {
}
private void saveChosenPatternAndFinish() {
- final boolean lockVirgin = !mLockPatternUtils.isPatternEverChosen();
+ LockPatternUtils utils = mChooseLockSettingsHelper.utils();
+ final boolean lockVirgin = !utils.isPatternEverChosen();
- mLockPatternUtils.saveLockPattern(mChosenPattern);
- mLockPatternUtils.setLockPatternEnabled(true);
+ utils.saveLockPattern(mChosenPattern);
+ utils.setLockPatternEnabled(true);
if (lockVirgin) {
- mLockPatternUtils.setVisiblePatternEnabled(true);
- mLockPatternUtils.setTactileFeedbackEnabled(false);
+ utils.setVisiblePatternEnabled(true);
+ utils.setTactileFeedbackEnabled(false);
+
+ // It's the first time we choose a lock pattern, so set the "disable
+ // lockscreen on security option" to the default value here. All other security
+ // types will be set correctly on first use.
+ // This is needed as otherwise the option will be enabled on first use.
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.LOCKSCREEN_DISABLE_ON_SECURITY, 0);
}
-
+
setResult(RESULT_FINISHED);
finish();
}
diff --git a/src/com/android/settings/ChooseLockPatternExample.java b/src/com/android/settings/ChooseLockPatternExample.java
index 77517b9d3d4..cba88b01cec 100644
--- a/src/com/android/settings/ChooseLockPatternExample.java
+++ b/src/com/android/settings/ChooseLockPatternExample.java
@@ -25,7 +25,6 @@
import android.widget.ImageView;
public class ChooseLockPatternExample extends Activity implements View.OnClickListener {
- private static final int REQUESTCODE_CHOOSE = 1;
private static final long START_DELAY = 1000;
protected static final String TAG = "Settings";
private View mNextButton;
@@ -38,26 +37,26 @@ public void run() {
startAnimation(mAnimation);
}
};
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_lock_pattern_example);
initViews();
}
-
+
@Override
protected void onResume() {
super.onResume();
mHandler.postDelayed(mRunnable, START_DELAY);
}
-
+
@Override
protected void onPause() {
super.onPause();
stopAnimation(mAnimation);
}
-
+
public void onClick(View v) {
if (v == mSkipButton) {
// Canceling, so finish all
@@ -66,37 +65,31 @@ public void onClick(View v) {
} else if (v == mNextButton) {
stopAnimation(mAnimation);
Intent intent = new Intent(this, ChooseLockPattern.class);
- startActivityForResult(intent, REQUESTCODE_CHOOSE);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUESTCODE_CHOOSE && resultCode == ChooseLockPattern.RESULT_FINISHED) {
- setResult(resultCode);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
finish();
}
}
-
+
private void initViews() {
mNextButton = findViewById(R.id.next_button);
mNextButton.setOnClickListener(this);
-
+
mSkipButton = findViewById(R.id.skip_button);
mSkipButton.setOnClickListener(this);
-
+
mImageView = (ImageView) findViewById(R.id.lock_anim);
mImageView.setBackgroundResource(R.drawable.lock_anim);
mImageView.setOnClickListener(this);
mAnimation = (AnimationDrawable) mImageView.getBackground();
}
-
+
protected void startAnimation(final AnimationDrawable animation) {
if (animation != null && !animation.isRunning()) {
animation.run();
}
}
-
+
protected void stopAnimation(final AnimationDrawable animation) {
if (animation != null && animation.isRunning()) animation.stop();
}
diff --git a/src/com/android/settings/ChooseLockPatternTutorial.java b/src/com/android/settings/ChooseLockPatternTutorial.java
index 6e92ca8eb14..ee0019f7065 100644
--- a/src/com/android/settings/ChooseLockPatternTutorial.java
+++ b/src/com/android/settings/ChooseLockPatternTutorial.java
@@ -24,26 +24,24 @@
import android.view.View;
public class ChooseLockPatternTutorial extends Activity implements View.OnClickListener {
- private static final int REQUESTCODE_EXAMPLE = 1;
-
private View mNextButton;
private View mSkipButton;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Don't show the tutorial if the user has seen it before.
- LockPatternUtils lockPatternUtils = new LockPatternUtils(getContentResolver());
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
if (savedInstanceState == null && lockPatternUtils.isPatternEverChosen()) {
- Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ChooseLockPattern");
+ Intent intent = new Intent(this, ChooseLockPattern.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(intent);
finish();
} else {
initViews();
}
}
-
+
private void initViews() {
setContentView(R.layout.choose_lock_pattern_tutorial);
mNextButton = findViewById(R.id.next_button);
@@ -58,18 +56,11 @@ public void onClick(View v) {
setResult(ChooseLockPattern.RESULT_FINISHED);
finish();
} else if (v == mNextButton) {
- startActivityForResult(new Intent(this, ChooseLockPatternExample.class),
- REQUESTCODE_EXAMPLE);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUESTCODE_EXAMPLE && resultCode == ChooseLockPattern.RESULT_FINISHED) {
- setResult(resultCode);
+ Intent intent = new Intent(this, ChooseLockPatternExample.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
finish();
}
}
-
}
diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java
new file mode 100644
index 00000000000..04d8342633a
--- /dev/null
+++ b/src/com/android/settings/ChooseLockSettingsHelper.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+
+import com.android.internal.widget.LockPatternUtils;
+
+public class ChooseLockSettingsHelper {
+ private LockPatternUtils mLockPatternUtils;
+ private Activity mActivity;
+
+ public ChooseLockSettingsHelper(Activity activity) {
+ mActivity = activity;
+ mLockPatternUtils = new LockPatternUtils(activity);
+ }
+
+ public LockPatternUtils utils() {
+ return mLockPatternUtils;
+ }
+
+ /**
+ * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
+ * @param message optional message to display about the action about to be done
+ * @param details optional detail message to display
+ * @return true if one exists and we launched an activity to confirm it
+ * @see #onActivityResult(int, int, android.content.Intent)
+ */
+ protected boolean launchConfirmationActivity(int request,
+ CharSequence message, CharSequence details) {
+ boolean launched = false;
+ switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
+ case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+ launched = confirmPattern(request, message, details);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_FINGER:
+ launched = confirmFinger(request, message, details);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ // TODO: update UI layout for ConfirmPassword to show message and details
+ launched = confirmPassword(request);
+ break;
+ }
+ return launched;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock pattern.
+ * @param message shown in header of ConfirmLockPattern if not null
+ * @param details shown in footer of ConfirmLockPattern if not null
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm pattern
+ */
+ private boolean confirmPattern(int request, CharSequence message, CharSequence details) {
+ if (!mLockPatternUtils.isLockPatternEnabled() || !mLockPatternUtils.savedPatternExists()) {
+ return false;
+ }
+ final Intent intent = new Intent();
+ // supply header and footer text in the intent
+ intent.putExtra(ConfirmLockPattern.HEADER_TEXT, message);
+ intent.putExtra(ConfirmLockPattern.FOOTER_TEXT, details);
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock finger.
+ * @param message shown in header of ConfirmLockFinger if not null
+ * @param details shown in footer of ConfirmLockFinger if not null
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm finger
+ */
+ private boolean confirmFinger(int request, CharSequence message, CharSequence details) {
+ if (!mLockPatternUtils.isLockFingerEnabled() || !mLockPatternUtils.savedFingerExists()) {
+ return false;
+ }
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockFinger");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+ /**
+ * Launch screen to confirm the existing lock password.
+ * @see #onActivityResult(int, int, android.content.Intent)
+ * @return true if we launched an activity to confirm password
+ */
+ private boolean confirmPassword(int request) {
+ if (!mLockPatternUtils.isLockPasswordEnabled()) return false;
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPassword");
+ mActivity.startActivityForResult(intent, request);
+ return true;
+ }
+
+
+}
diff --git a/src/com/android/settings/ConfirmLockFinger.java b/src/com/android/settings/ConfirmLockFinger.java
new file mode 100644
index 00000000000..8def9550a13
--- /dev/null
+++ b/src/com/android/settings/ConfirmLockFinger.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.Activity;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.view.Window;
+
+import android.util.Log;
+import android.os.Handler;
+
+import com.authentec.AuthentecHelper;
+
+public class ConfirmLockFinger extends Activity {
+
+ private static final boolean DEBUG = true;
+ private static final String TAG = "ConfirmLockFinger";
+ private static final String KEY_NUM_WRONG_ATTEMPTS = "num_wrong_attempts";
+
+ private LockPatternUtils mLockPatternUtils;
+ private int mNumWrongConfirmAttempts;
+ private CountDownTimer mCountdownTimer;
+
+ private TextView mHeaderTextView;
+ private TextView mFooterTextView;
+
+ private static Thread mExecutionThread = null;
+ private VerifyRunner mVerifyRunner = new VerifyRunner();
+ // The confirm screen would be put into lockout state every four bad swipes.
+ private static boolean sAttemptLockout;
+ private ConfirmLockFinger mConfirmLockFinger;
+ private AuthentecHelper fingerhelper;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Don't show the tutorial if the user has seen it before.
+ mLockPatternUtils = new LockPatternUtils(this);
+ mConfirmLockFinger = this;
+
+ fingerhelper = AuthentecHelper.getInstance(this);
+
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.confirm_lock_finger);
+
+ mHeaderTextView = (TextView) findViewById(R.id.headerText);
+ mFooterTextView = (TextView) findViewById(R.id.footerText);
+
+ if (savedInstanceState != null) {
+ mNumWrongConfirmAttempts = savedInstanceState.getInt(KEY_NUM_WRONG_ATTEMPTS);
+ }
+
+ // Initialize the verify runner.
+ mExecutionThread = null;
+ sAttemptLockout = false;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ // deliberately not calling super since we are managing this in full
+ outState.putInt(KEY_NUM_WRONG_ATTEMPTS, mNumWrongConfirmAttempts);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (DEBUG) Log.d(TAG, "onPause");
+
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (DEBUG) Log.d(TAG, "onResume");
+
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
+ if (deadline != 0) {
+ if (DEBUG) Log.d(TAG,"onResume: In lockout state");
+ handleAttemptLockout(deadline);
+ } else {
+ // The onFinish() method of the CountDownTimer object would not be
+ // called when the screen is off. So we need to reset the sAttemptLockout
+ // if the lockout has finished.
+ sAttemptLockout = false;
+ }
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+ if (hasWindowFocus) {
+ if (DEBUG) Log.d(TAG,"onWindowFocusChanged: has window focus");
+
+ if (mExecutionThread == null) {
+ if (DEBUG) Log.d(TAG,"onWindowFocusChanged: start verify runner from scratch");
+ mExecutionThread = new Thread(mVerifyRunner);
+ if (!sAttemptLockout) {
+ mExecutionThread.start();
+ }
+ } else {
+ if ((!sAttemptLockout) && !(mExecutionThread.isAlive())) {
+ if (DEBUG) Log.d(TAG,"onWindowFocusChanged: restart verify runner");
+ if (mExecutionThread.getState() == Thread.State.TERMINATED) {
+ // If the thread state is TERMINATED, it cannot be start() again.
+ // Create a thread for verification.
+ mExecutionThread = new Thread(mVerifyRunner);
+ }
+ mExecutionThread.start();
+ }
+ }
+ }
+ }
+
+ /**
+ * Provides a Runnable class to handle the finger
+ * verification
+ */
+ private class VerifyRunner implements Runnable {
+ public void run() {
+
+ // Clear header and footer text for a new verification.
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mHeaderTextView.setText("");
+ mFooterTextView.setText("");
+ }
+ });
+
+ try {
+ // Launch the LAP verify dialog. If user is authenticated, then finish with
+ // success. Otherwise, finish with cancel.
+
+ int iResult = 0;
+ try {
+ iResult = fingerhelper.fingerprintUnlock("lap-verify", ConfirmLockFinger.this);
+ } catch (Exception e) {
+ iResult = AuthentecHelper.eAM_STATUS_LIBRARY_NOT_AVAILABLE;
+ }
+
+ switch (iResult) {
+ case AuthentecHelper.eAM_STATUS_OK:
+ Log.i(TAG, "LAP Verify OK");
+ setResult(RESULT_OK);
+ finish();
+ break;
+
+ case AuthentecHelper.eAM_STATUS_NO_STORED_CREDENTIAL:
+ // Should never happen. But if that is the case, we return OK to
+ // let the confirmation pass.
+ Log.e(TAG, "No stored credential, returning OK");
+ setResult(RESULT_OK);
+ finish();
+ break;
+
+ case AuthentecHelper.eAM_STATUS_LIBRARY_NOT_AVAILABLE:
+ // Failed because library not available.
+ Log.e(TAG, "Library failed to load... cannot proceed!");
+ setResult(RESULT_CANCELED);
+ finish();
+ break;
+
+ case AuthentecHelper.eAM_STATUS_USER_CANCELED:
+ // Failed because user canceled.
+ Log.e(TAG, "Simulating device lock.\nYou may not cancel!");
+ setResult(RESULT_CANCELED);
+ finish();
+ break;
+
+ case AuthentecHelper.eAM_STATUS_UI_TIMEOUT:
+ // UI timeout, lockout for sometime.
+ Log.e(TAG, "UI timeout!");
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mHeaderTextView.setText(R.string.lockfinger_ui_timeout_header);
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+ handleAttemptLockout(deadline);
+ }
+ });
+ break;
+
+ case AuthentecHelper.eAM_STATUS_CREDENTIAL_LOCKED:
+ // Failed to verify for 4 times, lockout for sometime.
+ Log.e(TAG, "Credential locked!");
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mHeaderTextView.setText(R.string.lockfinger_too_many_bad_swipes_header);
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
+ handleAttemptLockout(deadline);
+ }
+ });
+ break;
+
+ default:
+ Log.e(TAG, "Other results: " + iResult);
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ } catch (Exception e) {e.printStackTrace();}
+
+ try {
+ Thread.sleep(1500);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void handleAttemptLockout(long elapsedRealtimeDeadline) {
+ // Indicate the lockout state.
+ sAttemptLockout = true;
+
+ long elapsedRealtime = SystemClock.elapsedRealtime();
+ mCountdownTimer = new CountDownTimer(
+ elapsedRealtimeDeadline - elapsedRealtime,
+ LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ final int secondsCountdown = (int) (millisUntilFinished / 1000);
+ mFooterTextView.setText(getString(
+ R.string.lockfinger_lockout_countdown_footer,
+ secondsCountdown));
+ }
+
+ @Override
+ public void onFinish() {
+ mNumWrongConfirmAttempts = 0;
+ if (DEBUG) Log.d(TAG, "handleAttemptLockout: onFinish");
+ sAttemptLockout = false;
+
+ // Start the verification if the confirm screen has the window focus.
+ if (hasWindowFocus()) {
+ if (mExecutionThread != null && !(mExecutionThread.isAlive())) {
+ if (DEBUG) Log.d(TAG,"Lockout onFinish: restart verify runner");
+ if (mExecutionThread.getState() == Thread.State.TERMINATED)
+ {
+ // If the thread state is TERMINATED, it cannot be start() again.
+ // Create a thread for verification.
+ mExecutionThread = new Thread(mVerifyRunner);
+ mExecutionThread.start();
+ }
+ else
+ {
+ mExecutionThread.start();
+ }
+ }
+ }
+ }
+ }.start();
+ }
+}
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
new file mode 100644
index 00000000000..6bc135b015e
--- /dev/null
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.PasswordEntryKeyboardHelper;
+import com.android.internal.widget.PasswordEntryKeyboardView;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.Editable;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+public class ConfirmLockPassword extends Activity implements OnClickListener,
+ OnEditorActionListener {
+ private static final long ERROR_MESSAGE_TIMEOUT = 3000;
+ private TextView mPasswordEntry;
+ private LockPatternUtils mLockPatternUtils;
+ private TextView mHeaderText;
+ private Handler mHandler = new Handler();
+ private PasswordEntryKeyboardHelper mKeyboardHelper;
+ private PasswordEntryKeyboardView mKeyboardView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mLockPatternUtils = new LockPatternUtils(this);
+ initViews();
+ }
+
+ private void initViews() {
+ final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality();
+ setContentView(R.layout.confirm_lock_password);
+ // Disable IME on our window since we provide our own keyboard
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+ findViewById(R.id.cancel_button).setOnClickListener(this);
+ findViewById(R.id.next_button).setOnClickListener(this);
+ mPasswordEntry = (TextView) findViewById(R.id.password_entry);
+ mPasswordEntry.setOnEditorActionListener(this);
+ mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
+ mHeaderText = (TextView) findViewById(R.id.headerText);
+ final boolean isAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
+ || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality;
+ mHeaderText.setText(isAlpha ? R.string.lockpassword_confirm_your_password_header
+ : R.string.lockpassword_confirm_your_pin_header);
+ mKeyboardHelper = new PasswordEntryKeyboardHelper(this, mKeyboardView, mPasswordEntry);
+ mKeyboardHelper.setKeyboardMode(isAlpha ? PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA
+ : PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mKeyboardView.requestFocus();
+ }
+
+ @Override
+ protected void onResume() {
+ // TODO Auto-generated method stub
+ super.onResume();
+ mKeyboardView.requestFocus();
+ }
+
+ private void handleNext() {
+ final String pin = mPasswordEntry.getText().toString();
+ if (mLockPatternUtils.checkPassword(pin)) {
+ setResult(RESULT_OK);
+ finish();
+ } else {
+ showError(R.string.lockpattern_need_to_unlock_wrong);
+ }
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.next_button:
+ handleNext();
+ break;
+
+ case R.id.cancel_button:
+ setResult(RESULT_CANCELED);
+ finish();
+ break;
+ }
+ }
+
+ private void showError(int msg) {
+ mHeaderText.setText(msg);
+ mPasswordEntry.setText(null);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mHeaderText.setText(R.string.lockpassword_confirm_your_password_header);
+ }
+ }, ERROR_MESSAGE_TIMEOUT);
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Check if this was the result of hitting the enter key
+ if (actionId == EditorInfo.IME_NULL) {
+ handleNext();
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index 44baccc6504..eb9a4d8e516 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -19,6 +19,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
+import com.android.internal.widget.LockPatternView.Cell;
import android.app.Activity;
import android.content.Intent;
@@ -79,7 +80,7 @@ private enum Stage {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ mLockPatternUtils = new LockPatternUtils(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.confirm_lock_pattern);
@@ -93,7 +94,7 @@ protected void onCreate(Bundle savedInstanceState) {
final LinearLayoutWithDefaultTouchRecepient topLayout
= (LinearLayoutWithDefaultTouchRecepient) findViewById(
R.id.topLayout);
- topLayout.setDefaultTouchRecepient(mLockPatternView);
+ topLayout.setDefaultTouchRecepient(mLockPatternView);
Intent intent = getIntent();
if (intent != null) {
@@ -160,7 +161,7 @@ private void updateStage(Stage stage) {
} else {
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_footer);
}
-
+
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
break;
@@ -175,7 +176,7 @@ private void updateStage(Stage stage) {
} else {
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_wrong_footer);
}
-
+
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
@@ -216,6 +217,10 @@ public void onPatternCleared() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
}
+ public void onPatternCellAdded(List| pattern) {
+
+ }
+
public void onPatternDetected(List pattern) {
if (mLockPatternUtils.checkPattern(pattern)) {
setResult(RESULT_OK);
diff --git a/src/com/android/settings/CredentialInstaller.java b/src/com/android/settings/CredentialInstaller.java
new file mode 100644
index 00000000000..7c63b1c17b5
--- /dev/null
+++ b/src/com/android/settings/CredentialInstaller.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.util.Log;
+
+/**
+ * Installs credentials to the system keystore. It reacts to the
+ * {@link Credentials#SYSTEM_INSTALL_ACTION} intent. All the key-value pairs in
+ * the intent are installed to the system keystore. For security reason, the
+ * current implementation limits that only com.android.certinstaller can use
+ * this service.
+ */
+public class CredentialInstaller extends Activity {
+ private static final String TAG = "CredentialInstaller";
+ private static final String UNLOCKING = "ulck";
+
+ private KeyStore mKeyStore = KeyStore.getInstance();
+ private boolean mUnlocking = false;
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (!"com.android.certinstaller".equals(getCallingPackage())) finish();
+
+ if (isKeyStoreUnlocked()) {
+ install();
+ } else if (!mUnlocking) {
+ mUnlocking = true;
+ Credentials.getInstance().unlock(this);
+ return;
+ }
+ finish();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outStates) {
+ super.onSaveInstanceState(outStates);
+ outStates.putBoolean(UNLOCKING, mUnlocking);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedStates) {
+ super.onRestoreInstanceState(savedStates);
+ mUnlocking = savedStates.getBoolean(UNLOCKING);
+ }
+
+ private void install() {
+ Intent intent = getIntent();
+ Bundle bundle = (intent == null) ? null : intent.getExtras();
+ if (bundle == null) return;
+ for (String key : bundle.keySet()) {
+ byte[] data = bundle.getByteArray(key);
+ if (data == null) continue;
+ boolean success = mKeyStore.put(key.getBytes(), data);
+ Log.d(TAG, "install " + key + ": " + data.length + " success? " + success);
+ if (!success) return;
+ }
+ setResult(RESULT_OK);
+ }
+
+ private boolean isKeyStoreUnlocked() {
+ return (mKeyStore.test() == KeyStore.NO_ERROR);
+ }
+}
diff --git a/src/com/android/settings/DateTimeSettingsSetupWizard.java b/src/com/android/settings/DateTimeSettingsSetupWizard.java
index 8dd970b0e9b..a6a60c1b2c9 100644
--- a/src/com/android/settings/DateTimeSettingsSetupWizard.java
+++ b/src/com/android/settings/DateTimeSettingsSetupWizard.java
@@ -20,7 +20,6 @@
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
-import android.widget.LinearLayout;
public class DateTimeSettingsSetupWizard extends DateTimeSettings implements OnClickListener {
private View mNextButton;
diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java
index 8eed5635018..0933d622ed8 100644
--- a/src/com/android/settings/DefaultRingtonePreference.java
+++ b/src/com/android/settings/DefaultRingtonePreference.java
@@ -42,11 +42,6 @@ protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) {
* doesn't make sense to show a 'Default' item.
*/
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
-
- /*
- * Similarly, 'Silent' shouldn't be shown here.
- */
- ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
}
@Override
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index c1da18a1413..a1459d93775 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -17,6 +17,7 @@
package com.android.settings;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.DialogInterface;
import android.os.BatteryManager;
import android.os.Bundle;
@@ -35,16 +36,26 @@ public class DevelopmentSettings extends PreferenceActivity
implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
private static final String ENABLE_ADB = "enable_adb";
+ private static final String ADB_TCPIP = "adb_over_network";
+ private static final String ADB_NOTIFY = "adb_notify";
private static final String KEEP_SCREEN_ON = "keep_screen_on";
private static final String ALLOW_MOCK_LOCATION = "allow_mock_location";
+ private static final String KILL_APP_LONGPRESS_BACK = "kill_app_longpress_back";
private CheckBoxPreference mEnableAdb;
+ private CheckBoxPreference mAdbOverNetwork;
+ private CheckBoxPreference mAdbNotify;
private CheckBoxPreference mKeepScreenOn;
private CheckBoxPreference mAllowMockLocation;
+ private CheckBoxPreference mKillAppLongpressBack;
+
+ private String mCurrentDialog;
// To track whether Yes was clicked in the adb warning dialog
private boolean mOkClicked;
+ private Dialog mOkDialog;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -52,71 +63,127 @@ protected void onCreate(Bundle icicle) {
addPreferencesFromResource(R.xml.development_prefs);
mEnableAdb = (CheckBoxPreference) findPreference(ENABLE_ADB);
+ mAdbOverNetwork = (CheckBoxPreference) findPreference(ADB_TCPIP);
+ mAdbNotify = (CheckBoxPreference) findPreference(ADB_NOTIFY);
mKeepScreenOn = (CheckBoxPreference) findPreference(KEEP_SCREEN_ON);
mAllowMockLocation = (CheckBoxPreference) findPreference(ALLOW_MOCK_LOCATION);
+ mKillAppLongpressBack = (CheckBoxPreference) findPreference(KILL_APP_LONGPRESS_BACK);
}
@Override
protected void onResume() {
super.onResume();
-
+
mEnableAdb.setChecked(Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ADB_ENABLED, 0) != 0);
+ mAdbOverNetwork.setChecked(Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ADB_PORT, 0) > 0);
+ mAdbNotify.setChecked(Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ADB_NOTIFY, 1) != 0);
+
mKeepScreenOn.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0) != 0);
mAllowMockLocation.setChecked(Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0);
+ mKillAppLongpressBack.setChecked(Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.KILL_APP_LONGPRESS_BACK, 0) != 0);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- // Those monkeys kept committing suicide, so we add this property
- // to disable this functionality
- if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) {
+ if (Utils.isMonkeyRunning()) {
return false;
}
if (preference == mEnableAdb) {
if (mEnableAdb.isChecked()) {
mOkClicked = false;
- new AlertDialog.Builder(this).setMessage(
+ if (mOkDialog != null) dismissDialog();
+ mOkDialog = new AlertDialog.Builder(this).setMessage(
getResources().getString(R.string.adb_warning_message))
.setTitle(R.string.adb_warning_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.yes, this)
.setNegativeButton(android.R.string.no, this)
- .show()
- .setOnDismissListener(this);
+ .show();
+ mCurrentDialog = ENABLE_ADB;
+ mOkDialog.setOnDismissListener(this);
} else {
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_ENABLED, 0);
}
+ } else if (preference == mAdbOverNetwork) {
+ if (mAdbOverNetwork.isChecked()) {
+ mOkClicked = false;
+ if (mOkDialog != null) dismissDialog();
+ mOkDialog = new AlertDialog.Builder(this).setMessage(
+ getResources().getString(R.string.adb_over_network_warning))
+ .setTitle(R.string.adb_over_network)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setPositiveButton(android.R.string.yes, this)
+ .setNegativeButton(android.R.string.no, this)
+ .show();
+ mCurrentDialog = ADB_TCPIP;
+ mOkDialog.setOnDismissListener(this);
+ } else {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_PORT, -1);
+ }
+ } else if (preference == mAdbNotify) {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_NOTIFY,
+ mAdbNotify.isChecked() ? 1 : 0);
} else if (preference == mKeepScreenOn) {
- Settings.System.putInt(getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN,
- mKeepScreenOn.isChecked() ?
+ Settings.System.putInt(getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ mKeepScreenOn.isChecked() ?
(BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB) : 0);
} else if (preference == mAllowMockLocation) {
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION,
mAllowMockLocation.isChecked() ? 1 : 0);
+ } else if (preference == mKillAppLongpressBack) {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.KILL_APP_LONGPRESS_BACK,
+ mKillAppLongpressBack.isChecked() ? 1 : 0);
}
-
+
return false;
}
+ private void dismissDialog() {
+ if (mOkDialog == null) return;
+ mOkDialog.dismiss();
+ mOkDialog = null;
+ }
+
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
mOkClicked = true;
- Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_ENABLED, 1);
+ if (mCurrentDialog.equals(ENABLE_ADB)) {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_ENABLED, 1);
+ } else {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ADB_PORT, 5555);
+ }
} else {
// Reset the toggle
- mEnableAdb.setChecked(false);
+ if (mCurrentDialog.equals(ENABLE_ADB)) {
+ mEnableAdb.setChecked(false);
+ } else {
+ mAdbOverNetwork.setChecked(false);
+ }
}
}
public void onDismiss(DialogInterface dialog) {
// Assuming that onClick gets called first
if (!mOkClicked) {
- mEnableAdb.setChecked(false);
+ if (mCurrentDialog.equals(ENABLE_ADB)) {
+ mEnableAdb.setChecked(false);
+ } else {
+ mAdbOverNetwork.setChecked(false);
+ }
}
}
+
+ @Override
+ public void onDestroy() {
+ dismissDialog();
+ super.onDestroy();
+ }
}
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
new file mode 100644
index 00000000000..005196e2f29
--- /dev/null
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteCallback;
+import android.text.TextUtils.TruncateAt;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AppSecurityPermissions;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class DeviceAdminAdd extends Activity {
+ static final String TAG = "DeviceAdminAdd";
+
+ static final int DIALOG_WARNING = 1;
+
+ private static final int MAX_ADD_MSG_LINES_PORTRAIT = 5;
+ private static final int MAX_ADD_MSG_LINES_LANDSCAPE = 2;
+ private static final int MAX_ADD_MSG_LINES = 15;
+
+ Handler mHandler;
+
+ DevicePolicyManager mDPM;
+ DeviceAdminInfo mDeviceAdmin;
+ CharSequence mAddMsgText;
+
+ TextView mTitle;
+ ImageView mAdminIcon;
+ TextView mAdminName;
+ TextView mAdminDescription;
+ TextView mAddMsg;
+ boolean mAddMsgEllipsized = true;
+ TextView mAdminWarning;
+ ViewGroup mAdminPolicies;
+ Button mActionButton;
+ Button mCancelButton;
+
+ View mSelectLayout;
+
+ final ArrayList mAddingPolicies = new ArrayList();
+ final ArrayList mActivePolicies = new ArrayList();
+
+ boolean mAdding;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mHandler = new Handler(getMainLooper());
+
+ mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ Log.w(TAG, "Can now start ADD_DEVICE_ADMIN as a new task");
+ finish();
+ return;
+ }
+
+ ComponentName cn = (ComponentName)getIntent().getParcelableExtra(
+ DevicePolicyManager.EXTRA_DEVICE_ADMIN);
+ if (cn == null) {
+ Log.w(TAG, "No component specified in " + getIntent().getAction());
+ finish();
+ return;
+ }
+ if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) {
+ // If this was an add request, then just exit immediately if the
+ // given component is already added.
+ if (mDPM.isAdminActive(cn)) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ return;
+ }
+ }
+
+ ActivityInfo ai;
+ try {
+ ai = getPackageManager().getReceiverInfo(cn,
+ PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ finish();
+ return;
+ }
+
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ try {
+ mDeviceAdmin= new DeviceAdminInfo(this, ri);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ finish();
+ return;
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to retrieve device policy " + cn, e);
+ finish();
+ return;
+ }
+
+ mAddMsgText = getIntent().getCharSequenceExtra(
+ DevicePolicyManager.EXTRA_ADD_EXPLANATION);
+
+ setContentView(R.layout.device_admin_add);
+
+ mTitle = (TextView)findViewById(R.id.title);
+ mAdminIcon = (ImageView)findViewById(R.id.admin_icon);
+ mAdminName = (TextView)findViewById(R.id.admin_name);
+ mAdminDescription = (TextView)findViewById(R.id.admin_description);
+
+ mAddMsg = (TextView)findViewById(R.id.add_msg);
+ mAddMsg.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ toggleMessageEllipsis(v);
+ }
+ });
+
+ // toggleMessageEllipsis also handles initial layout:
+ toggleMessageEllipsis(mAddMsg);
+
+ mAdminWarning = (TextView)findViewById(R.id.admin_warning);
+ mAdminPolicies = (ViewGroup)findViewById(R.id.admin_policies);
+ mCancelButton = (Button)findViewById(R.id.cancel_button);
+ mCancelButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ finish();
+ }
+ });
+ mActionButton = (Button)findViewById(R.id.action_button);
+ mActionButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ if (mAdding) {
+ try {
+ mDPM.setActiveAdmin(mDeviceAdmin.getComponent());
+ setResult(Activity.RESULT_OK);
+ } catch (RuntimeException e) {
+ // Something bad happened... could be that it was
+ // already set, though.
+ Log.w(TAG, "Exception trying to activate admin "
+ + mDeviceAdmin.getComponent(), e);
+ if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
+ setResult(Activity.RESULT_OK);
+ }
+ }
+ finish();
+ } else {
+ mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
+ new RemoteCallback(mHandler) {
+ @Override
+ protected void onResult(Bundle bundle) {
+ CharSequence msg = bundle != null
+ ? bundle.getCharSequence(
+ DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
+ : null;
+ if (msg == null) {
+ mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
+ finish();
+ } else {
+ Bundle args = new Bundle();
+ args.putCharSequence(
+ DeviceAdminReceiver.EXTRA_DISABLE_WARNING, msg);
+ showDialog(DIALOG_WARNING, args);
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateInterface();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id, Bundle args) {
+ switch (id) {
+ case DIALOG_WARNING: {
+ CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING);
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ DeviceAdminAdd.this);
+ builder.setMessage(msg);
+ builder.setPositiveButton(R.string.dlg_ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
+ finish();
+ }
+ });
+ builder.setNegativeButton(R.string.dlg_cancel, null);
+ return builder.create();
+ }
+ default:
+ return super.onCreateDialog(id, args);
+
+ }
+ }
+
+ static void setViewVisibility(ArrayList views, int visibility) {
+ final int N = views.size();
+ for (int i=0; i policies = mDeviceAdmin.getUsedPolicies();
+ for (int i=0; i policies = mDeviceAdmin.getUsedPolicies();
+ for (int i=0; i d.getWidth() ?
+ MAX_ADD_MSG_LINES_PORTRAIT : MAX_ADD_MSG_LINES_LANDSCAPE;
+ }
+
+}
diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java
new file mode 100644
index 00000000000..c3c74b6596e
--- /dev/null
+++ b/src/com/android/settings/DeviceAdminSettings.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteCallback;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+public class DeviceAdminSettings extends ListActivity {
+ static final String TAG = "DeviceAdminSettings";
+
+ static final int DIALOG_WARNING = 1;
+
+ DevicePolicyManager mDPM;
+ final HashSet mActiveAdmins = new HashSet();
+ final ArrayList mAvailableAdmins = new ArrayList();
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ setContentView(R.layout.device_admin_settings);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateList();
+ }
+
+ void updateList() {
+ mActiveAdmins.clear();
+ List cur = mDPM.getActiveAdmins();
+ if (cur != null) {
+ for (int i=0; i avail = getPackageManager().queryBroadcastReceivers(
+ new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
+ PackageManager.GET_META_DATA);
+ int count = avail == null ? 0 : avail.size();
+ for (int i=0; i tutorials = pm.queryIntentActivities(imeIntent, 0);
+ if(tutorials == null || tutorials.isEmpty()) {
+ getPreferenceScreen().removePreference(findPreference("system_tutorial"));
+ }
+
+ setStringSummary("device_cpu", getCPUInfo());
+ setStringSummary("device_memory", getMemAvail().toString()+" MB / "+getMemTotal().toString()+" MB");
setStringSummary("firmware_version", Build.VERSION.RELEASE);
+ findPreference("firmware_version").setEnabled(true);
setValueSummary("baseband_version", "gsm.version.baseband");
setStringSummary("device_model", Build.MODEL);
setStringSummary("build_number", Build.DISPLAY);
findPreference("kernel_version").setSummary(getFormattedKernelVersion());
+ setValueSummary("mod_version", "ro.modversion");
+ findPreference("mod_version").setEnabled(true);
+ setValueSummary("build_date", "ro.build.date");
+
+ // Remove Safety information preference if PROPERTY_URL_SAFETYLEGAL is not set
+ removePreferenceIfPropertyMissing(getPreferenceScreen(), "safetylegal",
+ PROPERTY_URL_SAFETYLEGAL);
/*
* Settings is a generic app and should not contain any device-specific
* info.
*/
-
+
// These are contained in the "container" preference group
PreferenceGroup parentPreference = (PreferenceGroup) findPreference(KEY_CONTAINER);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_TERMS,
@@ -76,7 +104,7 @@ protected void onCreate(Bundle icicle) {
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_TEAM,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
-
+
// These are contained by the root preference screen
parentPreference = getPreferenceScreen();
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference,
@@ -84,8 +112,52 @@ protected void onCreate(Bundle icicle) {
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_CONTRIBUTORS,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
+
+ // Read platform settings for additional system update setting
+ boolean mUpdateSettingAvailable =
+ getResources().getBoolean(R.bool.config_additional_system_update_setting_enable);
+
+ if(mUpdateSettingAvailable == false) {
+ getPreferenceScreen().removePreference(findPreference(KEY_UPDATE_SETTING));
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference.getKey().equals("firmware_version")
+ || preference.getKey().equals("mod_version")) {
+ System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
+ mHits[mHits.length-1] = SystemClock.uptimeMillis();
+ if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName("android",
+ com.android.internal.app.PlatLogoActivity.class.getName());
+ if (preference.getKey().equals("mod_version")) {
+ intent.putExtra("special", true);
+ }
+ try {
+ startActivity(intent);
+ } catch (Exception e) {
+ }
+ }
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
}
-
+
+ private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
+ String preference, String property ) {
+ if (SystemProperties.get(property).equals(""))
+ {
+ // Property is missing so remove preference from group
+ try {
+ preferenceGroup.removePreference(findPreference(preference));
+ } catch (RuntimeException e) {
+ Log.d(TAG, "Property '" + property + "' missing and no '"
+ + preference + "' preference");
+ }
+ }
+ }
+
private void setStringSummary(String preference, String value) {
try {
findPreference(preference).setSummary(value);
@@ -94,17 +166,126 @@ private void setStringSummary(String preference, String value) {
getResources().getString(R.string.device_info_default));
}
}
-
+
private void setValueSummary(String preference, String property) {
try {
findPreference(preference).setSummary(
- SystemProperties.get(property,
+ SystemProperties.get(property,
getResources().getString(R.string.device_info_default)));
} catch (RuntimeException e) {
}
}
+ private Long getMemTotal() {
+ Long total = null;
+ BufferedReader reader = null;
+
+ try {
+ // Grab a reader to /proc/meminfo
+ reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/meminfo")), 1000);
+
+ // Grab the first line which contains mem total
+ String line = reader.readLine();
+
+ // Split line on the colon, we need info to the right of the colon
+ String[] info = line.split(":");
+
+ // We have to remove the kb on the end
+ String[] memTotal = info[1].trim().split(" ");
+
+ // Convert kb into mb
+ total = Long.parseLong(memTotal[0]);
+ total = total / 1024;
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ // We don't want to return null so default to 0
+ total = Long.parseLong("0");
+ }
+ finally {
+ // Make sure the reader is closed no matter what
+ try { reader.close(); }
+ catch(Exception e) {}
+ reader = null;
+ }
+
+ return total;
+ }
+
+ private Long getMemAvail() {
+ Long avail = null;
+ BufferedReader reader = null;
+
+ try {
+ // Grab a reader to /proc/meminfo
+ reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/meminfo")), 1000);
+
+ // This is memTotal which we don't need
+ String line = reader.readLine();
+
+ // This is memFree which we need
+ line = reader.readLine();
+ String[] free = line.split(":");
+ // Have to remove the kb on the end
+ String [] memFree = free[1].trim().split(" ");
+
+ // This is Buffers which we don't need
+ line = reader.readLine();
+
+ // This is Cached which we need
+ line = reader.readLine();
+ String[] cached = line.split(":");
+ // Have to remove the kb on the end
+ String[] memCached = cached[1].trim().split(" ");
+
+ avail = Long.parseLong(memFree[0]) + Long.parseLong(memCached[0]);
+ avail = avail / 1024;
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ // We don't want to return null so default to 0
+ avail = Long.parseLong("0");
+ }
+ finally {
+ // Make sure the reader is closed no matter what
+ try { reader.close(); }
+ catch(Exception e) {}
+ reader = null;
+ }
+
+ return avail;
+ }
+
+ private String getCPUInfo() {
+ String[] info = null;
+ BufferedReader reader = null;
+
+ try {
+ // Grab a reader to /proc/cpuinfo
+ reader = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/cpuinfo")), 1000);
+
+ // Grab a single line from cpuinfo
+ String line = reader.readLine();
+
+ // Split on the colon, we need info to the right of colon
+ info = line.split(":");
+ }
+ catch(IOException io) {
+ io.printStackTrace();
+ info = new String[1];
+ info[1] = "error";
+ }
+ finally {
+ // Make sure the reader is closed no matter what
+ try { reader.close(); }
+ catch(Exception e) {}
+ reader = null;
+ }
+
+ return info[1];
+ }
+
private String getFormattedKernelVersion() {
String procVersionStr;
@@ -121,7 +302,7 @@ private String getFormattedKernelVersion() {
"\\w+\\s+" + /* ignore: version */
"([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */
"\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx@xxxxx.constant) */
- "\\([^)]+\\)\\s+" + /* ignore: (gcc ..) */
+ "\\((?:[^(]*\\([^)]*\\))?[^)]*\\)\\s+" + /* ignore: (gcc ..) */
"([^\\s]+)\\s+" + /* group 3: #26 */
"(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */
"(.+)"; /* group 4: date */
@@ -141,7 +322,7 @@ private String getFormattedKernelVersion() {
m.group(2)).append(" ").append(m.group(3)).append("\n")
.append(m.group(4))).toString();
}
- } catch (IOException e) {
+ } catch (IOException e) {
Log.e(TAG,
"IO Exception when getting kernel version for Device Info screen",
e);
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
new file mode 100644
index 00000000000..2dd86b21152
--- /dev/null
+++ b/src/com/android/settings/DisplaySettings.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
+import java.util.ArrayList;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.IWindowManager;
+
+public class DisplaySettings extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener {
+ private static final String TAG = "DisplaySettings";
+
+ /** If there is no setting in the provider, use this. */
+ private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000;
+
+ private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
+ private static final String KEY_ANIMATIONS = "animations";
+ private static final String KEY_ACCELEROMETER = "accelerometer";
+ private static final String IS_INACCURATE_PROXIMITY = "is_inaccurate_proximity";
+
+ private ListPreference mAnimations;
+ private CheckBoxPreference mAccelerometer;
+ private CheckBoxPreference mInaccurateProximityPref;
+
+ private float[] mAnimationScales;
+
+ private IWindowManager mWindowManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ContentResolver resolver = getContentResolver();
+ mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+
+ addPreferencesFromResource(R.xml.display_settings);
+
+ mAnimations = (ListPreference) findPreference(KEY_ANIMATIONS);
+ mAnimations.setOnPreferenceChangeListener(this);
+ mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
+ mAccelerometer.setPersistent(false);
+
+ ListPreference screenTimeoutPreference =
+ (ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
+ screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
+ resolver, SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
+ screenTimeoutPreference.setOnPreferenceChangeListener(this);
+ disableUnusableTimeouts(screenTimeoutPreference);
+
+ /* In-accurate proximity */
+ mInaccurateProximityPref = (CheckBoxPreference) findPreference(IS_INACCURATE_PROXIMITY);
+ if (mInaccurateProximityPref != null) {
+ mInaccurateProximityPref.setChecked(Settings.System.getInt(getContentResolver(),
+ Settings.System.INACCURATE_PROXIMITY_WORKAROUND, 0) == 1);
+ }
+ }
+
+ private void disableUnusableTimeouts(ListPreference screenTimeoutPreference) {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ final long maxTimeout = dpm != null ? dpm.getMaximumTimeToLock(null) : 0;
+ if (maxTimeout == 0) {
+ return; // policy not enforced
+ }
+ final CharSequence[] entries = screenTimeoutPreference.getEntries();
+ final CharSequence[] values = screenTimeoutPreference.getEntryValues();
+ ArrayList revisedEntries = new ArrayList();
+ ArrayList revisedValues = new ArrayList();
+ for (int i = 0; i < values.length; i++) {
+ long timeout = Long.valueOf(values[i].toString());
+ if (timeout <= maxTimeout) {
+ revisedEntries.add(entries[i]);
+ revisedValues.add(values[i]);
+ }
+ }
+ if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
+ screenTimeoutPreference.setEntries(
+ revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
+ screenTimeoutPreference.setEntryValues(
+ revisedValues.toArray(new CharSequence[revisedValues.size()]));
+ final int userPreference = Integer.valueOf(screenTimeoutPreference.getValue());
+ if (userPreference <= maxTimeout) {
+ screenTimeoutPreference.setValue(String.valueOf(userPreference));
+ } else {
+ // There will be no highlighted selection since nothing in the list matches
+ // maxTimeout. The user can still select anything less than maxTimeout.
+ // TODO: maybe append maxTimeout to the list and mark selected.
+ }
+ }
+ screenTimeoutPreference.setEnabled(revisedEntries.size() > 0);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ updateState(true);
+ }
+
+ private void updateState(boolean force) {
+ int animations = 0;
+ try {
+ mAnimationScales = mWindowManager.getAnimationScales();
+ } catch (RemoteException e) {
+ }
+ if (mAnimationScales != null) {
+ if (mAnimationScales.length >= 1) {
+ animations = ((int)(mAnimationScales[0]+.5f)) % 10;
+ }
+ if (mAnimationScales.length >= 2) {
+ animations += (((int)(mAnimationScales[1]+.5f)) & 0x7) * 10;
+ }
+ }
+ int idx = 0;
+ int best = 0;
+ CharSequence[] aents = mAnimations.getEntryValues();
+ for (int i=0; i best) {
+ best = val;
+ idx = i;
+ }
+ }
+ mAnimations.setValueIndex(idx);
+ updateAnimationsSummary(mAnimations.getValue());
+ mAccelerometer.setChecked(Settings.System.getInt(
+ getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
+ }
+
+ private void updateAnimationsSummary(Object value) {
+ CharSequence[] summaries = getResources().getTextArray(R.array.animations_summaries);
+ CharSequence[] values = mAnimations.getEntryValues();
+ for (int i=0; i= 1) {
+ mAnimationScales[0] = value%10;
+ }
+ if (mAnimationScales.length >= 2) {
+ mAnimationScales[1] = (value/10)%10;
+ }
+ try {
+ mWindowManager.setAnimationScales(mAnimationScales);
+ } catch (RemoteException e) {
+ }
+ updateAnimationsSummary(objValue);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist animation setting", e);
+ }
+
+ }
+ if (KEY_SCREEN_TIMEOUT.equals(key)) {
+ int value = Integer.parseInt((String) objValue);
+ try {
+ Settings.System.putInt(getContentResolver(),
+ SCREEN_OFF_TIMEOUT, value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist screen timeout setting", e);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/com/android/settings/DockSettings.java b/src/com/android/settings/DockSettings.java
new file mode 100644
index 00000000000..0d46ce9a9b2
--- /dev/null
+++ b/src/com/android/settings/DockSettings.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+
+import com.android.settings.bluetooth.DockEventReceiver;
+
+public class DockSettings extends PreferenceActivity {
+
+ private static final int DIALOG_NOT_DOCKED = 1;
+ private static final String KEY_AUDIO_SETTINGS = "dock_audio";
+ private static final String KEY_DOCK_SOUNDS = "dock_sounds";
+ private Preference mAudioSettings;
+ private CheckBoxPreference mDockSounds;
+ private Intent mDockIntent;
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_DOCK_EVENT)) {
+ handleDockChange(intent);
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ContentResolver resolver = getContentResolver();
+ addPreferencesFromResource(R.xml.dock_settings);
+
+ initDockSettings();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ IntentFilter filter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
+ registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterReceiver(mReceiver);
+ }
+
+ private void initDockSettings() {
+ ContentResolver resolver = getContentResolver();
+
+ mAudioSettings = findPreference(KEY_AUDIO_SETTINGS);
+ if (mAudioSettings != null) {
+ mAudioSettings.setSummary(R.string.dock_audio_summary_none);
+ }
+
+ mDockSounds = (CheckBoxPreference) findPreference(KEY_DOCK_SOUNDS);
+ mDockSounds.setPersistent(false);
+ mDockSounds.setChecked(Settings.System.getInt(resolver,
+ Settings.System.DOCK_SOUNDS_ENABLED, 0) != 0);
+ }
+
+ private void handleDockChange(Intent intent) {
+ if (mAudioSettings != null) {
+ int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 0);
+
+ boolean isBluetooth = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) != null;
+
+ if (!isBluetooth) {
+ // No dock audio if not on Bluetooth.
+ mAudioSettings.setEnabled(false);
+ mAudioSettings.setSummary(R.string.dock_audio_summary_unknown);
+ } else {
+ mAudioSettings.setEnabled(true);
+
+ mDockIntent = intent;
+ int resId = R.string.dock_audio_summary_unknown;
+ switch (dockState) {
+ case Intent.EXTRA_DOCK_STATE_CAR:
+ resId = R.string.dock_audio_summary_car;
+ break;
+ case Intent.EXTRA_DOCK_STATE_DESK:
+ resId = R.string.dock_audio_summary_desk;
+ break;
+ case Intent.EXTRA_DOCK_STATE_UNDOCKED:
+ resId = R.string.dock_audio_summary_none;
+ }
+ mAudioSettings.setSummary(resId);
+ }
+
+ if (dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ // remove undocked dialog if currently showing.
+ try {
+ dismissDialog(DIALOG_NOT_DOCKED);
+ } catch (IllegalArgumentException iae) {
+ // Maybe it was already dismissed
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference == mAudioSettings) {
+ int dockState = mDockIntent != null
+ ? mDockIntent.getIntExtra(Intent.EXTRA_DOCK_STATE, 0)
+ : Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ if (dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ showDialog(DIALOG_NOT_DOCKED);
+ } else {
+ Intent i = new Intent(mDockIntent);
+ i.setAction(DockEventReceiver.ACTION_DOCK_SHOW_UI);
+ i.setClass(this, DockEventReceiver.class);
+ sendBroadcast(i);
+ }
+ } else if (preference == mDockSounds) {
+ Settings.System.putInt(getContentResolver(), Settings.System.DOCK_SOUNDS_ENABLED,
+ mDockSounds.isChecked() ? 1 : 0);
+ }
+
+ return true;
+ }
+
+ @Override
+ public Dialog onCreateDialog(int id) {
+ if (id == DIALOG_NOT_DOCKED) {
+ return createUndockedMessage();
+ }
+ return null;
+ }
+
+ private Dialog createUndockedMessage() {
+ final AlertDialog.Builder ab = new AlertDialog.Builder(this);
+ ab.setTitle(R.string.dock_not_found_title);
+ ab.setMessage(R.string.dock_not_found_text);
+ ab.setPositiveButton(android.R.string.ok, null);
+ return ab.create();
+ }
+}
diff --git a/src/com/android/settings/EditPinPreference.java b/src/com/android/settings/EditPinPreference.java
index ee3143c3942..362bed1bd69 100644
--- a/src/com/android/settings/EditPinPreference.java
+++ b/src/com/android/settings/EditPinPreference.java
@@ -16,6 +16,7 @@
package com.android.settings;
+import android.app.Dialog;
import android.content.Context;
import android.preference.EditTextPreference;
import android.text.method.DigitsKeyListener;
@@ -24,15 +25,11 @@
import android.view.View;
import android.widget.EditText;
-import java.util.Map;
-
/**
* TODO: Add a soft dialpad for PIN entry.
*/
class EditPinPreference extends EditTextPreference {
- private boolean mDialogOpen;
-
interface OnPinEnteredListener {
void onPinEntered(EditPinPreference preference, boolean positiveResult);
}
@@ -50,13 +47,13 @@ public EditPinPreference(Context context, AttributeSet attrs, int defStyle) {
public void setOnPinEnteredListener(OnPinEnteredListener listener) {
mPinListener = listener;
}
-
+
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
-
+
final EditText editText = (EditText) view.findViewById(android.R.id.edit);
-
+
if (editText != null) {
editText.setSingleLine(true);
editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
@@ -65,20 +62,22 @@ protected void onBindDialogView(View view) {
}
public boolean isDialogOpen() {
- return mDialogOpen;
+ Dialog dialog = getDialog();
+ return dialog != null && dialog.isShowing();
}
-
+
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
- mDialogOpen = false;
if (mPinListener != null) {
mPinListener.onPinEntered(this, positiveResult);
}
}
-
+
public void showPinDialog() {
- mDialogOpen = true;
- showDialog(null);
+ Dialog dialog = getDialog();
+ if (dialog == null || !dialog.isShowing()) {
+ showDialog(null);
+ }
}
}
diff --git a/src/com/android/settings/GfxEngineRelayService.java b/src/com/android/settings/GfxEngineRelayService.java
new file mode 100644
index 00000000000..81fd9c771d7
--- /dev/null
+++ b/src/com/android/settings/GfxEngineRelayService.java
@@ -0,0 +1,128 @@
+package com.android.settings;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.authentec.TrueSuiteMobile.RelayReceiverService;
+
+public class GfxEngineRelayService extends Service {
+
+ public interface Receiver
+ {
+ public void receiveCommand(String command, String args);
+ }
+
+ static Receiver mLocalReceiver = null;
+ public static void setLocalReceiver(Receiver localReceiver) {
+ // first send any queued commands to the activity
+ while (!mCommandBuffer.isEmpty()) {
+ Command storedCommand = mCommandBuffer.remove(0);
+ if (null == localReceiver) continue;
+
+ // send the command on to the receiver
+ localReceiver.receiveCommand(
+ storedCommand.mCommand, storedCommand.mArguments);
+ }
+
+ // finally record who the receiver is
+ mLocalReceiver = localReceiver;
+ }
+
+ static private ArrayList mCommandBuffer = new ArrayList();
+ static private List mEventBuffer = new ArrayList();
+ static private Semaphore mEventBufferSemaphore = null;
+
+ private class Command {
+ public String mCommand;
+ public String mArguments;
+ public Command(String command, String arguments) {
+ mCommand = command;
+ mArguments = arguments;
+ }
+ }
+
+ static public void queueEvent(String event) {
+ if (null == mEventBufferSemaphore) return;
+ mEventBuffer.add(event);
+ mEventBufferSemaphore.release();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ /* when we're bound to, we want to have an empty event buffer */
+ mEventBuffer.clear();
+ mEventBufferSemaphore = new Semaphore(0);
+ return new RelayReceiverServiceImpl();
+ }
+
+ private class RelayReceiverServiceImpl extends RelayReceiverService.Stub
+ implements RelayReceiverService {
+
+ /* remote clients call sendCommand() when the GfxEngine has provided */
+ /* a new command to apply to the UI */
+ public void sendCommand(String command, String args) throws RemoteException {
+
+ /* if we've got a local receiver, pass the command to it */
+ if (null != mLocalReceiver) {
+ while (!mCommandBuffer.isEmpty()) {
+ // first pull items from the buffer. if anything is in here,
+ // it came in before the activity was ready to receive them.
+ Command storedCommand = mCommandBuffer.remove(0);
+ mLocalReceiver.receiveCommand(
+ storedCommand.mCommand, storedCommand.mArguments);
+ }
+ mLocalReceiver.receiveCommand(command, args);
+ }
+
+ else {
+ // append it to a buffer to be delivered later
+ mCommandBuffer.add(new Command(command, args));
+ }
+ }
+
+ /* remote clients call receiveEvent() to get the next event from the */
+ /* UI's event queue -- things like #cancel and #timeout */
+ public String receiveEvent() throws RemoteException {
+ /* block until there's something in the event queue */
+ try {
+ // mEventBufferSemaphore.acquire();
+
+ // This method runs in the service's main thread (and there's no way
+ // to move it to a child thread, since it needs to return an answer
+ // to the GfxEngine), and when the keyguard blocks here, Android has
+ // problems. So it's better to add a timeout to the block waiting.
+ if (!mEventBufferSemaphore.tryAcquire(10, TimeUnit.SECONDS)) {
+
+ // The GfxEngine is not currently expecting this exception and it will
+ // try to use the null pointer. We should probably fix this in the GfxEngine,
+ // but a short term solution is to return "" instead of null.
+ return "";
+ }
+ } catch (InterruptedException e) {
+ // return null;
+ return "";
+ }
+
+ /* remove the next event from the queue and return it */
+ if (mEventBuffer.isEmpty()) {
+ return "";
+ }
+ else{
+ return mEventBuffer.remove(0);
+ }
+ }
+
+ /* remote clients call receiveEvent() to release mEventBufferSemaphore */
+ public void quit() throws RemoteException {
+ mEventBufferSemaphore.release();
+ }
+ }
+
+}
diff --git a/src/com/android/settings/HostnamePreference.java b/src/com/android/settings/HostnamePreference.java
new file mode 100644
index 00000000000..e44ea17e97f
--- /dev/null
+++ b/src/com/android/settings/HostnamePreference.java
@@ -0,0 +1,111 @@
+package com.android.settings;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.preference.EditTextPreference;
+import android.provider.Settings;
+import android.text.InputFilter;
+import android.text.Spanned;
+import android.util.AttributeSet;
+import android.util.Log;
+
+public class HostnamePreference extends EditTextPreference {
+
+ private static final String TAG = "HostnamePreference";
+
+ private static final String PROP_HOSTNAME = "net.hostname";
+
+ private final String DEFAULT_HOSTNAME;
+
+ InputFilter mHostnameInputFilter = new InputFilter() {
+ @Override
+ public CharSequence filter(CharSequence source, int start, int end,
+ Spanned dest, int dstart, int dend) {
+
+ if (source.length() == 0)
+ return null;
+
+ // remove any character that is not alphanumeric, period, or hyphen
+ return source.subSequence(start, end).toString().replaceAll("[^-.a-zA-Z0-9]", "");
+ }
+ };
+
+ public HostnamePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // determine the default hostname
+ String id = Settings.Secure.getString(getContext().getContentResolver(),
+ Settings.Secure.ANDROID_ID);
+ if (id != null && id.length() > 0) {
+ DEFAULT_HOSTNAME = "android-".concat(id);
+ } else {
+ DEFAULT_HOSTNAME = "";
+ }
+
+ setSummary(getText());
+ getEditText().setFilters(new InputFilter[] { mHostnameInputFilter });
+ getEditText().setHint(DEFAULT_HOSTNAME);
+ }
+
+ public HostnamePreference(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.editTextPreferenceStyle);
+ }
+
+ public HostnamePreference(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ if (positiveResult) {
+ String hostname = getEditText().getText().toString();
+
+ // remove any preceding or succeeding periods or hyphens
+ hostname = hostname.replaceAll("(?:\\.|-)+$", "");
+ hostname = hostname.replaceAll("^(?:\\.|-)+", "");
+
+ if (hostname.length() == 0) {
+ if (DEFAULT_HOSTNAME.length() != 0) {
+ // if no hostname is given, use the default
+ hostname = DEFAULT_HOSTNAME;
+ } else {
+ // if no other name can be determined
+ // fall back on the current hostname
+ hostname = getText();
+ }
+ }
+ setText(hostname);
+ }
+ }
+
+ @Override
+ public void setText(String text) {
+ if (text == null) {
+ Log.e(TAG, "tried to set null hostname, request ignored");
+ return;
+ } else if (text.length() == 0) {
+ Log.w(TAG, "setting empty hostname");
+ } else {
+ Log.i(TAG, "hostname has been set: " + text);
+ }
+ SystemProperties.set(PROP_HOSTNAME, text);
+ persistHostname(text);
+ setSummary(text);
+ }
+
+ @Override
+ public String getText() {
+ return SystemProperties.get(PROP_HOSTNAME);
+ }
+
+ @Override
+ public void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ String hostname = getText();
+ persistHostname(hostname);
+ }
+
+ public void persistHostname(String hostname) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.DEVICE_HOSTNAME, hostname);
+ }
+}
diff --git a/src/com/android/settings/IccLockSettings.java b/src/com/android/settings/IccLockSettings.java
index 18beb3283ca..64945677623 100644
--- a/src/com/android/settings/IccLockSettings.java
+++ b/src/com/android/settings/IccLockSettings.java
@@ -119,6 +119,11 @@ static String getSummary(Context context) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (Utils.isMonkeyRunning()) {
+ finish();
+ return;
+ }
+
addPreferencesFromResource(R.xml.sim_lock_settings);
mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
@@ -261,10 +266,13 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
mPinToggle.setChecked(!mToState);
mDialogState = ICC_LOCK_MODE;
showPinDialog();
+ } else if (preference == mPinDialog) {
+ mDialogState = ICC_OLD_MODE;
+ return false;
}
return true;
}
-
+
private void tryChangeIccLockState() {
// Try to change icc lock. If it succeeds, toggle the lock state and
// reset dialog state. Else inject error message and show dialog again.
@@ -277,7 +285,6 @@ private void iccLockChanged(boolean success) {
if (success) {
mPinToggle.setChecked(mToState);
} else {
- // TODO: I18N
Toast.makeText(this, mRes.getString(R.string.sim_lock_failed), Toast.LENGTH_SHORT)
.show();
}
@@ -286,7 +293,6 @@ private void iccLockChanged(boolean success) {
private void iccPinChanged(boolean success) {
if (!success) {
- // TODO: I18N
Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
Toast.LENGTH_SHORT)
.show();
@@ -304,7 +310,7 @@ private void tryChangePin() {
mPhone.getIccCard().changeIccLockPassword(mOldPin,
mNewPin, callback);
}
-
+
private boolean reasonablePin(String pin) {
if (pin == null || pin.length() < MIN_PIN_LENGTH || pin.length() > MAX_PIN_LENGTH) {
return false;
@@ -312,11 +318,12 @@ private boolean reasonablePin(String pin) {
return true;
}
}
-
+
private void resetDialogState() {
mError = null;
mDialogState = ICC_OLD_MODE; // Default for when Change PIN is clicked
mPin = "";
setDialogValues();
+ mDialogState = OFF_MODE;
}
}
diff --git a/src/com/android/settings/IconPreferenceScreen.java b/src/com/android/settings/IconPreferenceScreen.java
new file mode 100644
index 00000000000..c7c53038ed9
--- /dev/null
+++ b/src/com/android/settings/IconPreferenceScreen.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+public class IconPreferenceScreen extends Preference {
+
+ private Drawable mIcon;
+
+ public IconPreferenceScreen(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public IconPreferenceScreen(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setLayoutResource(R.layout.preference_icon);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.IconPreferenceScreen, defStyle, 0);
+ mIcon = a.getDrawable(R.styleable.IconPreferenceScreen_icon);
+ }
+
+ @Override
+ public void onBindView(View view) {
+ super.onBindView(view);
+ ImageView imageView = (ImageView) view.findViewById(R.id.icon);
+ if (imageView != null && mIcon != null) {
+ imageView.setImageDrawable(mIcon);
+ }
+ }
+}
diff --git a/src/com/android/settings/IncreasingRingPreference.java b/src/com/android/settings/IncreasingRingPreference.java
new file mode 100644
index 00000000000..75ac91b8eba
--- /dev/null
+++ b/src/com/android/settings/IncreasingRingPreference.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.media.AudioManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.VolumePreference;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+public class IncreasingRingPreference extends VolumePreference implements
+ CheckBox.OnCheckedChangeListener {
+ private static final String TAG = "IncreasingRingPreference";
+
+ private CheckBox mEnabledCheckbox;
+
+ private TextView mMinVolumeTitle;
+ private SeekBar mMinVolumeSeekBar;
+ private TextView mRingVolumeNotice;
+
+ private TextView mIntervalTitle;
+ private Spinner mInterval;
+ private int[] mIntervalValues;
+
+ public IncreasingRingPreference(Context context, AttributeSet attrs) {
+ super(context, attrs, false);
+
+ setStreamType(AudioManager.STREAM_RING);
+
+ setDialogLayoutResource(R.layout.preference_dialog_increasing_ring);
+ setDialogIcon(R.drawable.ic_settings_sound);
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+ super.onBindDialogView(view);
+
+ ContentResolver cr = getContext().getContentResolver();
+
+ mEnabledCheckbox = (CheckBox) view.findViewById(R.id.increasing_ring);
+ mMinVolumeTitle = (TextView) view.findViewById(R.id.increasing_ring_min_volume_title);
+ mMinVolumeSeekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+ mRingVolumeNotice = (TextView) view.findViewById(R.id.increasing_ring_volume_notice);
+ mIntervalTitle = (TextView) view.findViewById(R.id.increasing_ring_interval_title);
+ mInterval = (Spinner) view.findViewById(R.id.increasing_ring_interval);
+ mIntervalValues = getContext().getResources().getIntArray(R.array.increasing_ring_interval_values);
+
+ mEnabledCheckbox.setOnCheckedChangeListener(this);
+ mEnabledCheckbox.setChecked(Settings.System.getInt(cr, Settings.System.INCREASING_RING, 0) == 1);
+ mMinVolumeSeekBar.setProgress(Settings.System.getInt(
+ cr, Settings.System.INCREASING_RING_MIN_VOLUME, 1));
+ int interval = Settings.System.getInt(cr, Settings.System.INCREASING_RING_INTERVAL, 0);
+ int index = 0;
+
+ for (int i = 0; i < mIntervalValues.length; i++) {
+ if (mIntervalValues[i] == interval) {
+ index = i;
+ break;
+ }
+ }
+ mInterval.setSelection(index);
+
+ AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ mMinVolumeSeekBar.setSecondaryProgress(am.getStreamVolume(AudioManager.STREAM_RING));
+
+ updateVolumeNoticeVisibility(mMinVolumeSeekBar.getProgress());
+ updateEnabledStates();
+ }
+
+ @Override
+ protected void onDialogClosed(boolean positiveResult) {
+ super.onDialogClosed(false);
+
+ if (positiveResult) {
+ boolean checked = mEnabledCheckbox.isChecked();
+ ContentResolver cr = getContext().getContentResolver();
+
+ Settings.System.putInt(cr, Settings.System.INCREASING_RING, checked ? 1 : 0);
+ Settings.System.putInt(cr, Settings.System.INCREASING_RING_INTERVAL,
+ mIntervalValues[mInterval.getSelectedItemPosition()]);
+ Settings.System.putInt(cr,
+ Settings.System.INCREASING_RING_MIN_VOLUME,
+ mMinVolumeSeekBar.getProgress());
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ updateVolumeNoticeVisibility(mMinVolumeSeekBar.getProgress());
+ updateEnabledStates();
+ }
+
+ @Override
+ public boolean onVolumeChange(SeekBarVolumizer volumizer, int value) {
+ boolean result = super.onVolumeChange(volumizer, value);
+ if (result) {
+ updateVolumeNoticeVisibility(value);
+ }
+ return result;
+ }
+
+ private void updateVolumeNoticeVisibility(int value) {
+ boolean visible = value > mMinVolumeSeekBar.getSecondaryProgress();
+ if (!mEnabledCheckbox.isChecked()) {
+ visible = false;
+ }
+ mRingVolumeNotice.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ private void updateEnabledStates() {
+ boolean enable = mEnabledCheckbox.isChecked();
+ mMinVolumeTitle.setEnabled(enable);
+ mMinVolumeSeekBar.setEnabled(enable);
+ mRingVolumeNotice.setEnabled(enable);
+ mIntervalTitle.setEnabled(enable);
+ mInterval.setEnabled(enable);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ if (mEnabledCheckbox != null) {
+ myState.mEnabled = mEnabledCheckbox.isChecked();
+ }
+ if (mInterval != null) {
+ myState.mIntervalSelection = mInterval.getSelectedItemPosition();
+ }
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ if (mEnabledCheckbox != null) {
+ mEnabledCheckbox.setChecked(myState.mEnabled);
+ }
+ if (mInterval != null) {
+ mInterval.setSelection(myState.mIntervalSelection);
+ }
+ }
+
+ private static class SavedState extends BaseSavedState {
+ boolean mEnabled;
+ int mIntervalSelection;
+
+ public SavedState(Parcel source) {
+ super(source);
+ mEnabled = source.readInt() != 0;
+ mIntervalSelection = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mEnabled ? 1 : 0);
+ dest.writeInt(mIntervalSelection);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/src/com/android/settings/InstalledAppDetails.java b/src/com/android/settings/InstalledAppDetails.java
deleted file mode 100644
index 5a4e672b9d5..00000000000
--- a/src/com/android/settings/InstalledAppDetails.java
+++ /dev/null
@@ -1,559 +0,0 @@
-
-
-/**
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package com.android.settings;
-
-import com.android.settings.R;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageStatsObserver;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageStats;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.text.format.Formatter;
-import android.util.Config;
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.List;
-import android.content.ComponentName;
-import android.view.View;
-import android.widget.AppSecurityPermissions;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * Activity to display application information from Settings. This activity presents
- * extended information associated with a package like code, data, total size, permissions
- * used by the application and also the set of default launchable activities.
- * For system applications, an option to clear user data is displayed only if data size is > 0.
- * System applications that do not want clear user data do not have this option.
- * For non-system applications, there is no option to clear data. Instead there is an option to
- * uninstall the application.
- */
-public class InstalledAppDetails extends Activity implements View.OnClickListener, DialogInterface.OnClickListener {
- private static final String TAG="InstalledAppDetails";
- private static final int _UNKNOWN_APP=R.string.unknown;
- private ApplicationInfo mAppInfo;
- private Button mAppButton;
- private Button mActivitiesButton;
- private boolean localLOGV = false;
- private TextView mAppVersion;
- private TextView mTotalSize;
- private TextView mAppSize;
- private TextView mDataSize;
- private PkgSizeObserver mSizeObserver;
- private ClearUserDataObserver mClearDataObserver;
- // Views related to cache info
- private View mCachePanel;
- private TextView mCacheSize;
- private Button mClearCacheButton;
- private ClearCacheObserver mClearCacheObserver;
- private Button mForceStopButton;
-
- PackageStats mSizeInfo;
- private Button mManageSpaceButton;
- private PackageManager mPm;
-
- //internal constants used in Handler
- private static final int OP_SUCCESSFUL = 1;
- private static final int OP_FAILED = 2;
- private static final int CLEAR_USER_DATA = 1;
- private static final int GET_PKG_SIZE = 2;
- private static final int CLEAR_CACHE = 3;
- private static final String ATTR_PACKAGE_STATS="PackageStats";
-
- // invalid size value used initially and also when size retrieval through PackageManager
- // fails for whatever reason
- private static final int SIZE_INVALID = -1;
-
- // Resource strings
- private CharSequence mInvalidSizeStr;
- private CharSequence mComputingStr;
- private CharSequence mAppButtonText;
-
- // Dialog identifiers used in showDialog
- private static final int DLG_BASE = 0;
- private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
- private static final int DLG_FACTORY_RESET = DLG_BASE + 2;
- private static final int DLG_APP_NOT_FOUND = DLG_BASE + 3;
- private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 4;
-
- // Possible btn states
- private enum AppButtonStates {
- CLEAR_DATA,
- UNINSTALL,
- FACTORY_RESET,
- NONE
- }
- private AppButtonStates mAppButtonState;
-
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case CLEAR_USER_DATA:
- processClearMsg(msg);
- break;
- case GET_PKG_SIZE:
- refreshSizeInfo(msg);
- break;
- case CLEAR_CACHE:
- // Refresh size info
- mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
- break;
- default:
- break;
- }
- }
- };
-
- class ClearUserDataObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- final Message msg = mHandler.obtainMessage(CLEAR_USER_DATA);
- msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
- mHandler.sendMessage(msg);
- }
- }
-
- class PkgSizeObserver extends IPackageStatsObserver.Stub {
- public int idx;
- public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) {
- Message msg = mHandler.obtainMessage(GET_PKG_SIZE);
- Bundle data = new Bundle();
- data.putParcelable(ATTR_PACKAGE_STATS, pStats);
- msg.setData(data);
- mHandler.sendMessage(msg);
-
- }
- }
-
- class ClearCacheObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- final Message msg = mHandler.obtainMessage(CLEAR_CACHE);
- msg.arg1 = succeeded?OP_SUCCESSFUL:OP_FAILED;
- mHandler.sendMessage(msg);
- }
- }
-
- private String getSizeStr(long size) {
- if (size == SIZE_INVALID) {
- return mInvalidSizeStr.toString();
- }
- return Formatter.formatFileSize(this, size);
- }
-
- /** Called when the activity is first created. */
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- // Get package manager
- mPm = getPackageManager();
- // Get application's name from intent
- Intent intent = getIntent();
- final String packageName = intent.getStringExtra(ManageApplications.APP_PKG_NAME);
- mComputingStr = getText(R.string.computing_size);
- // Try retrieving package stats again
- CharSequence totalSizeStr, appSizeStr, dataSizeStr;
- totalSizeStr = appSizeStr = dataSizeStr = mComputingStr;
- if(localLOGV) Log.i(TAG, "Have to compute package sizes");
- mSizeObserver = new PkgSizeObserver();
- try {
- mAppInfo = mPm.getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Exception when retrieving package:"+packageName, e);
- showDialogInner(DLG_APP_NOT_FOUND);
- return;
- }
- setContentView(R.layout.installed_app_details);
- //TODO download str and download url
- // Set default values on sizes
- mTotalSize = (TextView)findViewById(R.id.total_size_text);
- mTotalSize.setText(totalSizeStr);
- mAppSize = (TextView)findViewById(R.id.application_size_text);
- mAppSize.setText(appSizeStr);
- mDataSize = (TextView)findViewById(R.id.data_size_text);
- mDataSize.setText(dataSizeStr);
- // Get AppButton
- mAppButton = ((Button)findViewById(R.id.uninstall_button));
- // Get ManageSpaceButton
- mManageSpaceButton = (Button)findViewById(R.id.manage_space_button);
- if(mAppInfo.manageSpaceActivityName != null) {
- mManageSpaceButton.setVisibility(View.VISIBLE);
- mManageSpaceButton.setOnClickListener(this);
- }
- // Cache section
- mCachePanel = findViewById(R.id.cache_panel);
- mCacheSize = (TextView) findViewById(R.id.cache_size_text);
- mCacheSize.setText(mComputingStr);
- mClearCacheButton = (Button) findViewById(R.id.clear_cache_button);
- mForceStopButton = (Button) findViewById(R.id.force_stop_button);
- mForceStopButton.setOnClickListener(this);
- // Get list of preferred activities
- mActivitiesButton = (Button)findViewById(R.id.clear_activities_button);
- List prefActList = new ArrayList();
- // Intent list cannot be null. so pass empty list
- List intentList = new ArrayList();
- mPm.getPreferredActivities(intentList, prefActList, packageName);
- if(localLOGV) Log.i(TAG, "Have "+prefActList.size()+" number of activities in prefered list");
- TextView autoLaunchView = (TextView)findViewById(R.id.auto_launch);
- if(prefActList.size() <= 0) {
- // Disable clear activities button
- autoLaunchView.setText(R.string.auto_launch_disable_text);
- mActivitiesButton.setEnabled(false);
- } else {
- autoLaunchView.setText(R.string.auto_launch_enable_text);
- mActivitiesButton.setOnClickListener(this);
- }
-
- // Security permissions section
- LinearLayout permsView = (LinearLayout) findViewById(R.id.permissions_section);
- AppSecurityPermissions asp = new AppSecurityPermissions(this, packageName);
- if(asp.getPermissionCount() > 0) {
- permsView.setVisibility(View.VISIBLE);
- // Make the security sections header visible
- LinearLayout securityList = (LinearLayout) permsView.findViewById(
- R.id.security_settings_list);
- securityList.addView(asp.getPermissionsView());
- } else {
- permsView.setVisibility(View.GONE);
- }
- }
-
- private void refreshAppAttributes(PackageInfo pkgInfo) {
- setAppLabelAndIcon();
- // Version number of application
- setAppVersion(pkgInfo);
- setAppBtnState();
- // Refresh size info
- if (mAppInfo != null && mAppInfo.packageName != null) {
- mPm.getPackageSizeInfo(mAppInfo.packageName, mSizeObserver);
- }
- }
-
- // Utility method to set applicaiton label and icon.
- private void setAppLabelAndIcon() {
- ((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mAppInfo.loadIcon(mPm));
- //set application name TODO version
- CharSequence appName = mAppInfo.loadLabel(mPm);
- if(appName == null) {
- appName = getString(_UNKNOWN_APP);
- }
- ((TextView)findViewById(R.id.app_name)).setText(appName);
- }
-
- // Utility method to set application version
- private void setAppVersion(PackageInfo pkgInfo) {
- // Version number of application
- mAppVersion = ((TextView)findViewById(R.id.app_version));
- if (pkgInfo != null) {
- mAppVersion.setVisibility(View.VISIBLE);
- mAppVersion.setText(getString(R.string.version_text,
- String.valueOf(pkgInfo.versionCode)));
- } else {
- mAppVersion.setVisibility(View.GONE);
- }
- }
-
- // Utility method to set button state
- private void setAppBtnState() {
- boolean visible = true;
- if ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- mAppButtonState = AppButtonStates.FACTORY_RESET;
- mAppButtonText = getText(R.string.app_factory_reset);
- } else {
- if ((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
- // Hide button if diableClearUserData is set
- mAppButtonState = AppButtonStates.NONE;
- visible = false;
- } else {
- mAppButtonState = AppButtonStates.CLEAR_DATA;
- mAppButtonText = getText(R.string.clear_user_data_text);
- }
- }
- } else {
- mAppButtonState = AppButtonStates.UNINSTALL;
- mAppButtonText = getText(R.string.uninstall_text);
- }
- if(visible) {
- mAppButton.setText(mAppButtonText);
- mAppButton.setVisibility(View.VISIBLE);
- } else {
- mAppButton.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- PackageInfo pkgInfo;
- // Get application info again to refresh changed properties of application
- try {
- mAppInfo = mPm.getApplicationInfo(mAppInfo.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
- pkgInfo = mPm.getPackageInfo(mAppInfo.packageName, 0);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Exception when retrieving package:" + mAppInfo.packageName, e);
- showDialogInner(DLG_APP_NOT_FOUND);
- return;
- }
- refreshAppAttributes(pkgInfo);
- }
-
- private void setIntentAndFinish(boolean finish, boolean appChanged) {
- if(localLOGV) Log.i(TAG, "appChanged="+appChanged);
- Intent intent = new Intent();
- intent.putExtra(ManageApplications.APP_CHG, appChanged);
- setResult(ManageApplications.RESULT_OK, intent);
- mAppButton.setEnabled(false);
- if(finish) {
- finish();
- }
- }
-
- /*
- * Private method to handle get size info notification from observer when
- * the async operation from PackageManager is complete. The current user data
- * info has to be refreshed in the manage applications screen as well as the current screen.
- */
- private void refreshSizeInfo(Message msg) {
- boolean changed = false;
- PackageStats newPs = msg.getData().getParcelable(ATTR_PACKAGE_STATS);
- long newTot = newPs.cacheSize+newPs.codeSize+newPs.dataSize;
- if(mSizeInfo == null) {
- mSizeInfo = newPs;
- String str = getSizeStr(newTot);
- mTotalSize.setText(str);
- mAppSize.setText(getSizeStr(newPs.codeSize));
- mDataSize.setText(getSizeStr(newPs.dataSize));
- mCacheSize.setText(getSizeStr(newPs.cacheSize));
- } else {
- long oldTot = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
- if(newTot != oldTot) {
- String str = getSizeStr(newTot);
- mTotalSize.setText(str);
- changed = true;
- }
- if(newPs.codeSize != mSizeInfo.codeSize) {
- mAppSize.setText(getSizeStr(newPs.codeSize));
- changed = true;
- }
- if(newPs.dataSize != mSizeInfo.dataSize) {
- mDataSize.setText(getSizeStr(newPs.dataSize));
- changed = true;
- }
- if(newPs.cacheSize != mSizeInfo.cacheSize) {
- mCacheSize.setText(getSizeStr(newPs.cacheSize));
- changed = true;
- }
- if(changed) {
- mSizeInfo = newPs;
- }
- }
-
- long data = mSizeInfo.dataSize;
- // Disable button if data is 0
- if(mAppButtonState != AppButtonStates.NONE){
- mAppButton.setText(mAppButtonText);
- if((mAppButtonState == AppButtonStates.CLEAR_DATA) && (data == 0)) {
- mAppButton.setEnabled(false);
- } else {
- mAppButton.setEnabled(true);
- mAppButton.setOnClickListener(this);
- }
- }
- refreshCacheInfo(newPs.cacheSize);
- }
-
- private void refreshCacheInfo(long cacheSize) {
- // Set cache info
- mCacheSize.setText(getSizeStr(cacheSize));
- if (cacheSize <= 0) {
- mClearCacheButton.setEnabled(false);
- } else {
- mClearCacheButton.setOnClickListener(this);
- }
- }
-
- /*
- * Private method to handle clear message notification from observer when
- * the async operation from PackageManager is complete
- */
- private void processClearMsg(Message msg) {
- int result = msg.arg1;
- String packageName = mAppInfo.packageName;
- if(result == OP_SUCCESSFUL) {
- Log.i(TAG, "Cleared user data for system package:"+packageName);
- mPm.getPackageSizeInfo(packageName, mSizeObserver);
- } else {
- mAppButton.setText(R.string.clear_user_data_text);
- mAppButton.setEnabled(true);
- }
- }
-
- /*
- * Private method to initiate clearing user data when the user clicks the clear data
- * button for a system package
- */
- private void initiateClearUserDataForSysPkg() {
- mAppButton.setEnabled(false);
- //invoke uninstall or clear user data based on sysPackage
- String packageName = mAppInfo.packageName;
- Log.i(TAG, "Clearing user data for system package");
- if(mClearDataObserver == null) {
- mClearDataObserver = new ClearUserDataObserver();
- }
- ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- boolean res = am.clearApplicationUserData(packageName, mClearDataObserver);
- if(!res) {
- // Clearing data failed for some obscure reason. Just log error for now
- Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
- showDialogInner(DLG_CANNOT_CLEAR_DATA);
- } else {
- mAppButton.setText(R.string.recompute_size);
- }
- }
-
- private void showDialogInner(int id) {
- //removeDialog(id);
- showDialog(id);
- }
-
- @Override
- public Dialog onCreateDialog(int id) {
- switch (id) {
- case DLG_CLEAR_DATA:
- return new AlertDialog.Builder(this)
- .setTitle(getString(R.string.clear_data_dlg_title))
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getString(R.string.clear_data_dlg_text))
- .setPositiveButton(R.string.dlg_ok, this)
- .setNegativeButton(R.string.dlg_cancel, this)
- .create();
- case DLG_FACTORY_RESET:
- return new AlertDialog.Builder(this)
- .setTitle(getString(R.string.app_factory_reset_dlg_title))
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getString(R.string.app_factory_reset_dlg_text))
- .setPositiveButton(R.string.dlg_ok, this)
- .setNegativeButton(R.string.dlg_cancel, this)
- .create();
- case DLG_APP_NOT_FOUND:
- return new AlertDialog.Builder(this)
- .setTitle(getString(R.string.app_not_found_dlg_title))
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getString(R.string.app_not_found_dlg_title))
- .setNeutralButton(getString(R.string.dlg_ok),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //force to recompute changed value
- setIntentAndFinish(true, true);
- }
- })
- .create();
- case DLG_CANNOT_CLEAR_DATA:
- return new AlertDialog.Builder(this)
- .setTitle(getString(R.string.clear_failed_dlg_title))
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getString(R.string.clear_failed_dlg_text))
- .setNeutralButton(R.string.dlg_ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- //force to recompute changed value
- setIntentAndFinish(false, false);
- }
- })
- .create();
- }
- return null;
- }
-
- private void uninstallPkg(String packageName) {
- // Create new intent to launch Uninstaller activity
- Uri packageURI = Uri.parse("package:"+packageName);
- Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
- startActivity(uninstallIntent);
- setIntentAndFinish(true, true);
- }
-
- /*
- * Method implementing functionality of buttons clicked
- * @see android.view.View.OnClickListener#onClick(android.view.View)
- */
- public void onClick(View v) {
- String packageName = mAppInfo.packageName;
- if(v == mAppButton) {
- if (mAppButtonState == AppButtonStates.CLEAR_DATA) {
- showDialogInner(DLG_CLEAR_DATA);
- } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) {
- showDialogInner(DLG_FACTORY_RESET);
- } else if (mAppButtonState == AppButtonStates.UNINSTALL) {
- uninstallPkg(packageName);
- }
- } else if(v == mActivitiesButton) {
- mPm.clearPackagePreferredActivities(packageName);
- mActivitiesButton.setEnabled(false);
- } else if(v == mManageSpaceButton) {
- Intent intent = new Intent(Intent.ACTION_DEFAULT);
- intent.setClassName(mAppInfo.packageName, mAppInfo.manageSpaceActivityName);
- startActivityForResult(intent, -1);
- } else if (v == mClearCacheButton) {
- // Lazy initialization of observer
- if (mClearCacheObserver == null) {
- mClearCacheObserver = new ClearCacheObserver();
- }
- mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
- } else if (v == mForceStopButton) {
- ActivityManager am = (ActivityManager)getSystemService(
- Context.ACTIVITY_SERVICE);
- am.restartPackage(packageName);
- }
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if(which == AlertDialog.BUTTON_POSITIVE) {
- if (mAppButtonState == AppButtonStates.CLEAR_DATA) {
- // Invoke uninstall or clear user data based on sysPackage
- initiateClearUserDataForSysPkg();
- } else if (mAppButtonState == AppButtonStates.FACTORY_RESET) {
- // Initiate package installer to delete package
- uninstallPkg(mAppInfo.packageName);
- }
- } else {
- //cancel do nothing just retain existing screen
- }
- }
-}
-
diff --git a/src/com/android/settings/Item.java b/src/com/android/settings/Item.java
new file mode 100644
index 00000000000..4a1a1586580
--- /dev/null
+++ b/src/com/android/settings/Item.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Florian Sundermann
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import android.graphics.drawable.Drawable;
+
+public class Item extends SubItem {
+ private final ArrayList fItems = new ArrayList();
+ private String fPackageName;
+
+ public Item(String name, Drawable image) {
+ super(name, image);
+ }
+
+ public ArrayList getItems() {
+ return fItems;
+ }
+
+ @Override
+ public String getName() {
+ if (fItems.size() == 1)
+ return fItems.get(0).getName();
+ else
+ return super.getName();
+ }
+
+ @Override
+ public Drawable getImage() {
+ if (fItems.size() == 1)
+ return fItems.get(0).getImage();
+ else
+ return super.getImage();
+ }
+
+ public void setPackageName(String aValue) {
+ fPackageName = aValue;
+ }
+
+ public String getPackageName() {
+ return fPackageName;
+ }
+
+ public void sort() {
+ Collections.sort(fItems, new Comparator() {
+
+ @Override
+ public int compare(SubItem object1, SubItem object2) {
+ return object1.getName().compareToIgnoreCase(object2.getName());
+ }
+
+ });
+ }
+}
diff --git a/src/com/android/settings/ItemAdapter.java b/src/com/android/settings/ItemAdapter.java
new file mode 100644
index 00000000000..d629be29672
--- /dev/null
+++ b/src/com/android/settings/ItemAdapter.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Florian Sundermann
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+
+public class ItemAdapter extends ArrayAdapter {
+ private final ArrayList items;
+ private final Context fContext;
+
+ public ItemAdapter(Context context, int textViewResourceId, ArrayList items) {
+ super(context, textViewResourceId, items);
+ this.items = items;
+ fContext = context;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = (LayoutInflater)fContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ v = vi.inflate(R.layout.appwidgetpicker, null);
+ }
+ SubItem o = items.get(position);
+ v.setTag(o);
+ if (o != null) {
+ TextView tv = (TextView) v.findViewById(R.id.appwidgetpicker_textview);
+ TextView count_view = (TextView) v.findViewById(R.id.appwidgetpicker_count);
+ ImageView iv = (ImageView) v.findViewById(R.id.appwidgetpicker_imageview);
+ if (tv != null) {
+ tv.setText(o.getName());
+ }
+ if (count_view != null) {
+ if (o instanceof Item) {
+ int cnt = ((Item)o).getItems().size();
+ if (cnt > 1) {
+ count_view.setText(String.format(fContext.getString(R.string.widget_count), cnt));
+ count_view.setVisibility(View.VISIBLE);
+ } else
+ count_view.setVisibility(View.GONE);
+ } else
+ count_view.setVisibility(View.GONE);
+ }
+ if(iv != null){
+ iv.setImageDrawable(o.getImage());
+ }
+ }
+ return v;
+ }
+}
diff --git a/src/com/android/settings/LanguageSettings.java b/src/com/android/settings/LanguageSettings.java
index cbab3901981..37671f07f5f 100644
--- a/src/com/android/settings/LanguageSettings.java
+++ b/src/com/android/settings/LanguageSettings.java
@@ -43,19 +43,23 @@
public class LanguageSettings extends PreferenceActivity {
+ private static final String KEY_PHONE_LANGUAGE = "phone_language";
+ private static final String KEY_KEYBOARD_SETTINGS_CATEGORY = "keyboard_settings_category";
+ private static final String KEY_HARDKEYBOARD_CATEGORY = "hardkeyboard_category";
private boolean mHaveHardKeyboard;
private List mInputMethodProperties;
private List mCheckboxes;
+ private Preference mLanguagePref;
final TextUtils.SimpleStringSplitter mStringColonSplitter
= new TextUtils.SimpleStringSplitter(':');
private String mLastInputMethodId;
private String mLastTickedInputMethodId;
-
- private String mRootDirectory;
+ private AlertDialog mDialog = null;
+
static public String getInputMethodIdFromKey(String key) {
return key;
}
@@ -68,13 +72,15 @@ protected void onCreate(Bundle icicle) {
if (getAssets().getLocales().length == 1) {
getPreferenceScreen().
- removePreference(findPreference("language_category"));
+ removePreference(findPreference(KEY_PHONE_LANGUAGE));
+ } else {
+ mLanguagePref = findPreference(KEY_PHONE_LANGUAGE);
}
Configuration config = getResources().getConfiguration();
if (config.keyboard != Configuration.KEYBOARD_QWERTY) {
getPreferenceScreen().removePreference(
- getPreferenceScreen().findPreference("hardkeyboard_category"));
+ getPreferenceScreen().findPreference(KEY_HARDKEYBOARD_CATEGORY));
} else {
mHaveHardKeyboard = true;
}
@@ -95,7 +101,8 @@ private void onCreateIMM() {
mLastInputMethodId = Settings.Secure.getString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
- PreferenceGroup textCategory = (PreferenceGroup) findPreference("text_category");
+ PreferenceGroup keyboardSettingsCategory = (PreferenceGroup) findPreference(
+ KEY_KEYBOARD_SETTINGS_CATEGORY);
int N = (mInputMethodProperties == null ? 0 : mInputMethodProperties
.size());
@@ -111,14 +118,18 @@ private void onCreateIMM() {
CheckBoxPreference chkbxPref = new CheckBoxPreference(this);
chkbxPref.setKey(prefKey);
chkbxPref.setTitle(label);
- textCategory.addPreference(chkbxPref);
+ keyboardSettingsCategory.addPreference(chkbxPref);
mCheckboxes.add(chkbxPref);
}
// If setting activity is available, add a setting screen entry.
if (null != property.getSettingsActivity()) {
PreferenceScreen prefScreen = new PreferenceScreen(this, null);
- prefScreen.setKey(property.getSettingsActivity());
+ String settingsActivity = property.getSettingsActivity();
+ if (settingsActivity.lastIndexOf("/") < 0) {
+ settingsActivity = property.getPackageName() + "/" + settingsActivity;
+ }
+ prefScreen.setKey(settingsActivity);
prefScreen.setTitle(label);
if (N == 1) {
prefScreen.setSummary(getString(R.string.onscreen_keyboard_settings_summary));
@@ -127,7 +138,7 @@ private void onCreateIMM() {
R.string.input_methods_settings_label_format, label);
prefScreen.setSummary(settingsLabel);
}
- textCategory.addPreference(prefScreen);
+ keyboardSettingsCategory.addPreference(prefScreen);
}
}
}
@@ -158,6 +169,15 @@ protected void onResume() {
}
}
mLastTickedInputMethodId = null;
+
+ if (mLanguagePref != null) {
+ Configuration conf = getResources().getConfiguration();
+ String locale = conf.locale.getDisplayName(conf.locale);
+ if (locale != null && locale.length() > 1) {
+ locale = Character.toUpperCase(locale.charAt(0)) + locale.substring(1);
+ mLanguagePref.setSummary(locale);
+ }
+ }
}
@Override
@@ -165,7 +185,8 @@ protected void onPause() {
super.onPause();
StringBuilder builder = new StringBuilder(256);
-
+ StringBuilder disabledSysImes = new StringBuilder(256);
+
int firstEnabled = -1;
int N = mInputMethodProperties.size();
for (int i = 0; i < N; ++i) {
@@ -184,6 +205,12 @@ protected void onPause() {
} else if (hasIt) {
mLastInputMethodId = mLastTickedInputMethodId;
}
+ // If it's a disabled system ime, add it to the disabled list so that it
+ // doesn't get enabled automatically on any changes to the package list
+ if (pref != null && !pref.isChecked() && systemIme && mHaveHardKeyboard) {
+ if (disabledSysImes.length() > 0) disabledSysImes.append(":");
+ disabledSysImes.append(id);
+ }
}
// If the last input method is unset, set it as the first enabled one.
@@ -197,6 +224,8 @@ protected void onPause() {
Settings.Secure.putString(getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+ Settings.Secure.putString(getContentResolver(),
+ Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, disabledSysImes.toString());
Settings.Secure.putString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD,
mLastInputMethodId != null ? mLastInputMethodId : "");
@@ -206,9 +235,7 @@ protected void onPause() {
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
// Input Method stuff
- // Those monkeys kept committing suicide, so we add this property
- // to disable this functionality
- if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) {
+ if (Utils.isMonkeyRunning()) {
return false;
}
@@ -233,12 +260,12 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen
if (selImi == null) {
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
- AlertDialog d = (new AlertDialog.Builder(this))
+ if (mDialog != null && mDialog.isShowing()) {
+ mDialog.dismiss();
+ }
+ mDialog = (new AlertDialog.Builder(this))
.setTitle(android.R.string.dialog_alert_title)
.setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(getString(R.string.ime_security_warning,
- selImi.getServiceInfo().applicationInfo.loadLabel(
- getPackageManager())))
.setCancelable(true)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@@ -246,16 +273,17 @@ public void onClick(DialogInterface dialog, int which) {
chkPref.setChecked(true);
mLastTickedInputMethodId = id;
}
-
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
-
})
.create();
- d.show();
+ mDialog.setMessage(getString(R.string.ime_security_warning,
+ selImi.getServiceInfo().applicationInfo.loadLabel(
+ getPackageManager())));
+ mDialog.show();
} else if (id.equals(mLastTickedInputMethodId)) {
mLastTickedInputMethodId = null;
}
@@ -265,6 +293,11 @@ public void onClick(DialogInterface dialog, int which) {
String activityName = pref.getKey();
String packageName = activityName.substring(0, activityName
.lastIndexOf("."));
+ int slash = activityName.indexOf("/");
+ if (slash > 0) {
+ packageName = activityName.substring(0, slash);
+ activityName = activityName.substring(slash + 1);
+ }
if (activityName.length() > 0) {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setClassName(packageName, activityName);
@@ -275,4 +308,13 @@ public void onClick(DialogInterface dialog, int which) {
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mDialog != null) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ }
+
}
diff --git a/src/com/android/settings/LauncherAppWidgetBinder.java b/src/com/android/settings/LauncherAppWidgetBinder.java
deleted file mode 100644
index 98ea246650b..00000000000
--- a/src/com/android/settings/LauncherAppWidgetBinder.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.app.Activity;
-import android.appwidget.AppWidgetManager;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.content.ComponentName;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.BaseColumns;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-public class LauncherAppWidgetBinder extends Activity {
- private static final String TAG = "LauncherAppWidgetBinder";
- private static final boolean LOGD = true;
-
- static final String AUTHORITY = "com.android.launcher.settings";
- static final String TABLE_FAVORITES = "favorites";
-
- static final String EXTRA_BIND_SOURCES = "com.android.launcher.settings.bindsources";
- static final String EXTRA_BIND_TARGETS = "com.android.launcher.settings.bindtargets";
-
- static final String EXTRA_APPWIDGET_BITMAPS = "com.android.camera.appwidgetbitmaps";
-
- /**
- * {@link ContentProvider} constants pulled over from Launcher
- */
- static final class LauncherProvider implements BaseColumns {
- static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_FAVORITES);
-
- static final String ITEM_TYPE = "itemType";
- static final String APPWIDGET_ID = "appWidgetId";
- static final String ICON = "icon";
-
- static final int ITEM_TYPE_APPWIDGET = 4;
- static final int ITEM_TYPE_WIDGET_CLOCK = 1000;
- static final int ITEM_TYPE_WIDGET_SEARCH = 1001;
- static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
- }
-
- static final String[] BIND_PROJECTION = new String[] {
- LauncherProvider._ID,
- LauncherProvider.ITEM_TYPE,
- LauncherProvider.APPWIDGET_ID,
- LauncherProvider.ICON,
- };
-
- static final int INDEX_ID = 0;
- static final int INDEX_ITEM_TYPE = 1;
- static final int INDEX_APPWIDGET_ID = 2;
- static final int INDEX_ICON = 3;
-
- static final ComponentName BIND_PHOTO_APPWIDGET = new ComponentName("com.android.camera",
- "com.android.camera.PhotoAppWidgetBind");
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- finish();
-
- // This helper reaches into the Launcher database and binds any unlinked
- // widgets. If will remove any items that can't be bound successfully.
- // We protect this binder at the manifest level by asserting the caller
- // has the Launcher WRITE_SETTINGS permission.
-
- final Intent intent = getIntent();
- final Bundle extras = intent.getExtras();
-
- int[] bindSources = null;
- ArrayList bindTargets = null;
- Exception exception = null;
-
- try {
- bindSources = extras.getIntArray(EXTRA_BIND_SOURCES);
- bindTargets = intent.getParcelableArrayListExtra(EXTRA_BIND_TARGETS);
- } catch (ClassCastException ex) {
- exception = ex;
- }
-
- if (exception != null || bindSources == null || bindTargets == null ||
- bindSources.length != bindTargets.size()) {
- Log.w(TAG, "Problem reading incoming bind request, or invalid request", exception);
- return;
- }
-
- final String selectWhere = buildOrWhereString(LauncherProvider.ITEM_TYPE, bindSources);
-
- final ContentResolver resolver = getContentResolver();
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
-
- boolean foundPhotoAppWidgets = false;
- final ArrayList photoAppWidgetIds = new ArrayList();
- final ArrayList photoBitmaps = new ArrayList();
-
- Cursor c = null;
-
- try {
- c = resolver.query(LauncherProvider.CONTENT_URI,
- BIND_PROJECTION, selectWhere, null, null);
-
- if (LOGD) Log.d(TAG, "found bind cursor count="+c.getCount());
-
- final ContentValues values = new ContentValues();
- while (c != null && c.moveToNext()) {
- long favoriteId = c.getLong(INDEX_ID);
- int itemType = c.getInt(INDEX_ITEM_TYPE);
- int appWidgetId = c.getInt(INDEX_APPWIDGET_ID);
- byte[] iconData = c.getBlob(INDEX_ICON);
-
- // Find the binding target for this type
- ComponentName targetAppWidget = null;
- for (int i = 0; i < bindSources.length; i++) {
- if (bindSources[i] == itemType) {
- targetAppWidget = bindTargets.get(i);
- break;
- }
- }
-
- if (LOGD) Log.d(TAG, "found matching targetAppWidget="+targetAppWidget.toString()+" for favoriteId="+favoriteId);
-
- boolean bindSuccess = false;
- try {
- appWidgetManager.bindAppWidgetId(appWidgetId, targetAppWidget);
- bindSuccess = true;
- } catch (RuntimeException ex) {
- Log.w(TAG, "Problem binding widget", ex);
- }
-
- // Handle special case of photo widget by loading bitmap and
- // preparing for later binding
- if (bindSuccess && iconData != null &&
- itemType == LauncherProvider.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
- Bitmap bitmap = BitmapFactory.decodeByteArray(iconData, 0, iconData.length);
-
- photoAppWidgetIds.add(appWidgetId);
- photoBitmaps.add(bitmap);
- foundPhotoAppWidgets = true;
- }
-
- if (LOGD) Log.d(TAG, "after finished, success="+bindSuccess);
-
- // Depending on success, update launcher or remove item
- Uri favoritesUri = ContentUris.withAppendedId(LauncherProvider.CONTENT_URI, favoriteId);
- if (bindSuccess) {
- values.clear();
- values.put(LauncherProvider.ITEM_TYPE, LauncherProvider.ITEM_TYPE_APPWIDGET);
- values.putNull(LauncherProvider.ICON);
- resolver.update(favoritesUri, values, null, null);
- } else {
- resolver.delete(favoritesUri, null, null);
- }
-
- }
- } catch (SQLException ex) {
- Log.w(TAG, "Problem while binding appWidgetIds for Launcher", ex);
- } finally {
- if (c != null) {
- c.close();
- }
- }
-
- if (foundPhotoAppWidgets) {
- // Convert appWidgetIds into int[]
- final int N = photoAppWidgetIds.size();
- final int[] photoAppWidgetIdsArray = new int[N];
- for (int i = 0; i < N; i++) {
- photoAppWidgetIdsArray[i] = photoAppWidgetIds.get(i);
- }
-
- // Launch intent over to handle bitmap binding, but we don't need to
- // wait around for the result.
- final Intent bindIntent = new Intent();
- bindIntent.setComponent(BIND_PHOTO_APPWIDGET);
-
- final Bundle bindExtras = new Bundle();
- bindExtras.putIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS, photoAppWidgetIdsArray);
- bindExtras.putParcelableArrayList(EXTRA_APPWIDGET_BITMAPS, photoBitmaps);
- bindIntent.putExtras(bindExtras);
-
- startActivity(bindIntent);
- }
-
- if (LOGD) Log.d(TAG, "completely finished with binding for Launcher");
- }
-
- /**
- * Build a query string that will match any row where the column matches
- * anything in the values list.
- */
- static String buildOrWhereString(String column, int[] values) {
- StringBuilder selectWhere = new StringBuilder();
- for (int i = values.length - 1; i >= 0; i--) {
- selectWhere.append(column).append("=").append(values[i]);
- if (i > 0) {
- selectWhere.append(" OR ");
- }
- }
- return selectWhere.toString();
- }
-
-}
diff --git a/src/com/android/settings/LocalePicker.java b/src/com/android/settings/LocalePicker.java
index d31e82ca71d..dcd61414b2c 100644
--- a/src/com/android/settings/LocalePicker.java
+++ b/src/com/android/settings/LocalePicker.java
@@ -19,7 +19,7 @@
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
-import android.backup.BackupManager;
+import android.app.backup.BackupManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.RemoteException;
@@ -37,6 +37,7 @@
public class LocalePicker extends ListActivity {
private static final String TAG = "LocalePicker";
+ private static final boolean DEBUG = false;
Loc[] mLocales;
String[] mSpecialLocaleCodes;
@@ -90,8 +91,9 @@ public void onCreate(Bundle icicle) {
Locale l = new Locale(language, country);
if (finalSize == 0) {
- Log.v(TAG, "adding initial "+
- toTitleCase(l.getDisplayLanguage(l)));
+ if (DEBUG) {
+ Log.v(TAG, "adding initial "+ toTitleCase(l.getDisplayLanguage(l)));
+ }
preprocess[finalSize++] =
new Loc(toTitleCase(l.getDisplayLanguage(l)), l);
} else {
@@ -101,13 +103,16 @@ public void onCreate(Bundle icicle) {
// diff lang -> insert ours with lang-only name
if (preprocess[finalSize-1].locale.getLanguage().equals(
language)) {
- Log.v(TAG, "backing up and fixing "+
- preprocess[finalSize-1].label+" to "+
- getDisplayName(preprocess[finalSize-1].locale));
+ if (DEBUG) {
+ Log.v(TAG, "backing up and fixing "+
+ preprocess[finalSize-1].label+" to "+
+ getDisplayName(preprocess[finalSize-1].locale));
+ }
preprocess[finalSize-1].label = toTitleCase(
getDisplayName(preprocess[finalSize-1].locale));
- Log.v(TAG, " and adding "+
- toTitleCase(getDisplayName(l)));
+ if (DEBUG) {
+ Log.v(TAG, " and adding "+ toTitleCase(getDisplayName(l)));
+ }
preprocess[finalSize++] =
new Loc(toTitleCase(getDisplayName(l)), l);
} else {
@@ -117,7 +122,9 @@ public void onCreate(Bundle icicle) {
} else {
displayName = toTitleCase(l.getDisplayLanguage(l));
}
- Log.v(TAG, "adding "+displayName);
+ if (DEBUG) {
+ Log.v(TAG, "adding "+displayName);
+ }
preprocess[finalSize++] = new Loc(displayName, l);
}
}
diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java
deleted file mode 100644
index 9cb421786a4..00000000000
--- a/src/com/android/settings/ManageApplications.java
+++ /dev/null
@@ -1,1879 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import com.android.settings.R;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageStatsObserver;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageStats;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.text.format.Formatter;
-import android.util.Config;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.AdapterView.OnItemClickListener;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Activity to pick an application that will be used to display installation information and
- * options to uninstall/delete user data for system applications. This activity
- * can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE
- * intent.
- * Initially a compute in progress message is displayed while the application retrieves
- * the list of application information from the PackageManager. The size information
- * for each package is refreshed to the screen. The resource(app description and
- * icon) information for each package is not available yet, so some default values for size
- * icon and descriptions are used initially. Later the resource information for each
- * application is retrieved and dynamically updated on the screen.
- * A Broadcast receiver registers for package additions or deletions when the activity is
- * in focus. If the user installs or deletes packages when the activity has focus, the receiver
- * gets notified and proceeds to add/delete these packages from the list on the screen.
- * This is an unlikely scenario but could happen. The entire list gets created every time
- * the activity's onStart gets invoked. This is to avoid having the receiver for the entire
- * life cycle of the application.
- * The applications can be sorted either alphabetically or
- * based on size(descending). If this activity gets launched under low memory
- * situations(A low memory notification dispatches intent
- * ACTION_MANAGE_PACKAGE_STORAGE) the list is sorted per size.
- * If the user selects an application, extended info(like size, uninstall/clear data options,
- * permissions info etc.,) is displayed via the InstalledAppDetails activity.
- */
-public class ManageApplications extends ListActivity implements
- OnItemClickListener, DialogInterface.OnCancelListener,
- DialogInterface.OnClickListener {
- // TAG for this activity
- private static final String TAG = "ManageApplications";
- private static final String PREFS_NAME = "ManageAppsInfo.prefs";
- private static final String PREF_DISABLE_CACHE = "disableCache";
-
- // Log information boolean
- private boolean localLOGV = Config.LOGV || false;
- private static final boolean DEBUG_SIZE = false;
- private static final boolean DEBUG_TIME = false;
-
- // attributes used as keys when passing values to InstalledAppDetails activity
- public static final String APP_PKG_PREFIX = "com.android.settings.";
- public static final String APP_PKG_NAME = APP_PKG_PREFIX+"ApplicationPkgName";
- public static final String APP_CHG = APP_PKG_PREFIX+"changed";
-
- // attribute name used in receiver for tagging names of added/deleted packages
- private static final String ATTR_PKG_NAME="p";
- private static final String ATTR_PKGS="ps";
- private static final String ATTR_STATS="ss";
- private static final String ATTR_SIZE_STRS="fs";
-
- private static final String ATTR_GET_SIZE_STATUS="passed";
- private static final String ATTR_PKG_STATS="s";
- private static final String ATTR_PKG_SIZE_STR="f";
-
- // constant value that can be used to check return code from sub activity.
- private static final int INSTALLED_APP_DETAILS = 1;
-
- // sort order that can be changed through the menu can be sorted alphabetically
- // or size(descending)
- private static final int MENU_OPTIONS_BASE = 0;
- public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 0;
- public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 1;
- // Filter options used for displayed list of applications
- public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 2;
- public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 3;
- public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 4;
- public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 5;
- // Alert Dialog presented to user to find out the filter option
- AlertDialog mAlertDlg;
- // sort order
- private int mSortOrder = SORT_ORDER_ALPHA;
- // Filter value
- int mFilterApps = FILTER_APPS_ALL;
-
- // Custom Adapter used for managing items in the list
- private AppInfoAdapter mAppInfoAdapter;
-
- // messages posted to the handler
- private static final int HANDLER_MESSAGE_BASE = 0;
- private static final int INIT_PKG_INFO = HANDLER_MESSAGE_BASE+1;
- private static final int COMPUTE_BULK_SIZE = HANDLER_MESSAGE_BASE+2;
- private static final int REMOVE_PKG = HANDLER_MESSAGE_BASE+3;
- private static final int REORDER_LIST = HANDLER_MESSAGE_BASE+4;
- private static final int ADD_PKG_START = HANDLER_MESSAGE_BASE+5;
- private static final int ADD_PKG_DONE = HANDLER_MESSAGE_BASE+6;
- private static final int REFRESH_LABELS = HANDLER_MESSAGE_BASE+7;
- private static final int REFRESH_DONE = HANDLER_MESSAGE_BASE+8;
- private static final int NEXT_LOAD_STEP = HANDLER_MESSAGE_BASE+9;
- private static final int COMPUTE_END = HANDLER_MESSAGE_BASE+10;
- private static final int REFRESH_ICONS = HANDLER_MESSAGE_BASE+11;
-
- // observer object used for computing pkg sizes
- private PkgSizeObserver mObserver;
- // local handle to PackageManager
- private PackageManager mPm;
- // Broadcast Receiver object that receives notifications for added/deleted
- // packages
- private PackageIntentReceiver mReceiver;
- // atomic variable used to track if computing pkg sizes is in progress. should be volatile?
-
- private boolean mComputeSizes = false;
- // default icon thats used when displaying applications initially before resource info is
- // retrieved
- private Drawable mDefaultAppIcon;
-
- // temporary dialog displayed while the application info loads
- private static final int DLG_BASE = 0;
- private static final int DLG_LOADING = DLG_BASE + 1;
-
- // Size resource used for packages whose size computation failed for some reason
- private CharSequence mInvalidSizeStr;
- private CharSequence mComputingSizeStr;
-
- // map used to store list of added and removed packages. Immutable Boolean
- // variables indicate if a package has been added or removed. If a package is
- // added or deleted multiple times a single entry with the latest operation will
- // be recorded in the map.
- private Map mAddRemoveMap;
-
- // layout inflater object used to inflate views
- private LayoutInflater mInflater;
-
- // invalid size value used initially and also when size retrieval through PackageManager
- // fails for whatever reason
- private static final int SIZE_INVALID = -1;
-
- // debug boolean variable to test delays from PackageManager API's
- private boolean DEBUG_PKG_DELAY = false;
-
- // Thread to load resources
- ResourceLoaderThread mResourceThread;
- private TaskRunner mSizeComputor;
-
- String mCurrentPkgName;
-
- // Cache application attributes
- private AppInfoCache mCache = new AppInfoCache();
-
- // empty message displayed when list is empty
- private TextView mEmptyView;
-
- // Boolean variables indicating state
- private boolean mLoadLabels = false;
- private boolean mSizesFirst = false;
- // ListView used to display list
- private ListView mListView;
- // State variables used to figure out menu options and also
- // initiate the first computation and loading of resources
- private boolean mJustCreated = true;
- private boolean mFirst = false;
- private long mLoadTimeStart;
- private boolean mSetListViewLater = true;
-
- /*
- * Handler class to handle messages for various operations
- * Most of the operations that effect Application related data
- * are posted as messages to the handler to avoid synchronization
- * when accessing these structures.
- * When the size retrieval gets kicked off for the first time, a COMPUTE_PKG_SIZE_START
- * message is posted to the handler which invokes the getSizeInfo for the pkg at index 0
- * When the PackageManager's asynchronous call back through
- * PkgSizeObserver.onGetStatsCompleted gets invoked, the application resources like
- * label, description, icon etc., is loaded in the same thread and these values are
- * set on the observer. The observer then posts a COMPUTE_PKG_SIZE_DONE message
- * to the handler. This information is updated on the AppInfoAdapter associated with
- * the list view of this activity and size info retrieval is initiated for the next package as
- * indicated by mComputeIndex
- * When a package gets added while the activity has focus, the PkgSizeObserver posts
- * ADD_PKG_START message to the handler. If the computation is not in progress, the size
- * is retrieved for the newly added package through the observer object and the newly
- * installed app info is updated on the screen. If the computation is still in progress
- * the package is added to an internal structure and action deferred till the computation
- * is done for all the packages.
- * When a package gets deleted, REMOVE_PKG is posted to the handler
- * if computation is not in progress(as indicated by
- * mDoneIniting), the package is deleted from the displayed list of apps. If computation is
- * still in progress the package is added to an internal structure and action deferred till
- * the computation is done for all packages.
- * When the sizes of all packages is computed, the newly
- * added or removed packages are processed in order.
- * If the user changes the order in which these applications are viewed by hitting the
- * menu key, REORDER_LIST message is posted to the handler. this sorts the list
- * of items based on the sort order.
- */
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- boolean status;
- long size;
- String formattedSize;
- ApplicationInfo info;
- Bundle data;
- String pkgName = null;
- AppInfo appInfo;
- data = msg.getData();
- if(data != null) {
- pkgName = data.getString(ATTR_PKG_NAME);
- }
- switch (msg.what) {
- case INIT_PKG_INFO:
- if(localLOGV) Log.i(TAG, "Message INIT_PKG_INFO, justCreated = " + mJustCreated);
- List newList = null;
- if (!mJustCreated) {
- // Add or delete newly created packages by comparing lists
- newList = getInstalledApps(FILTER_APPS_ALL);
- updateAppList(newList);
- }
- // Retrieve the package list and init some structures
- initAppList(newList, mFilterApps);
- mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
- break;
- case COMPUTE_BULK_SIZE:
- if(localLOGV) Log.i(TAG, "Message COMPUTE_BULK_PKG_SIZE");
- String[] pkgs = data.getStringArray(ATTR_PKGS);
- long[] sizes = data.getLongArray(ATTR_STATS);
- String[] formatted = data.getStringArray(ATTR_SIZE_STRS);
- if(pkgs == null || sizes == null || formatted == null) {
- Log.w(TAG, "Ignoring message");
- break;
- }
- mAppInfoAdapter.bulkUpdateSizes(pkgs, sizes, formatted);
- break;
- case COMPUTE_END :
- mComputeSizes = true;
- mFirst = true;
- mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
- break;
- case REMOVE_PKG:
- if(localLOGV) Log.i(TAG, "Message REMOVE_PKG");
- if(pkgName == null) {
- Log.w(TAG, "Ignoring message:REMOVE_PKG for null pkgName");
- break;
- }
- if (!mComputeSizes) {
- Boolean currB = mAddRemoveMap.get(pkgName);
- if (currB == null || (currB.equals(Boolean.TRUE))) {
- mAddRemoveMap.put(pkgName, Boolean.FALSE);
- }
- break;
- }
- List pkgList = new ArrayList();
- pkgList.add(pkgName);
- mAppInfoAdapter.removeFromList(pkgList);
- break;
- case REORDER_LIST:
- if(localLOGV) Log.i(TAG, "Message REORDER_LIST");
- int menuOption = msg.arg1;
- if((menuOption == SORT_ORDER_ALPHA) ||
- (menuOption == SORT_ORDER_SIZE)) {
- // Option to sort list
- if (menuOption != mSortOrder) {
- mSortOrder = menuOption;
- if (localLOGV) Log.i(TAG, "Changing sort order to "+mSortOrder);
- mAppInfoAdapter.sortList(mSortOrder);
- }
- } else if(menuOption != mFilterApps) {
- // Option to filter list
- mFilterApps = menuOption;
- boolean ret = mAppInfoAdapter.resetAppList(mFilterApps);
- if(!ret) {
- // Reset cache
- mFilterApps = FILTER_APPS_ALL;
- mHandler.sendEmptyMessage(INIT_PKG_INFO);
- sendMessageToHandler(REORDER_LIST, menuOption);
- }
- }
- break;
- case ADD_PKG_START:
- if(localLOGV) Log.i(TAG, "Message ADD_PKG_START");
- if(pkgName == null) {
- Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName");
- break;
- }
- if (!mComputeSizes || !mLoadLabels) {
- Boolean currB = mAddRemoveMap.get(pkgName);
- if (currB == null || (currB.equals(Boolean.FALSE))) {
- mAddRemoveMap.put(pkgName, Boolean.TRUE);
- }
- break;
- }
- try {
- info = mPm.getApplicationInfo(pkgName, 0);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Couldnt find application info for:"+pkgName);
- break;
- }
- mObserver.invokeGetSizeInfo(pkgName);
- break;
- case ADD_PKG_DONE:
- if(localLOGV) Log.i(TAG, "Message ADD_PKG_DONE");
- if(pkgName == null) {
- Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName");
- break;
- }
- status = data.getBoolean(ATTR_GET_SIZE_STATUS);
- if (status) {
- size = data.getLong(ATTR_PKG_STATS);
- formattedSize = data.getString(ATTR_PKG_SIZE_STR);
- int idx = mAppInfoAdapter.getIndex(pkgName);
- if (idx == -1) {
- mAppInfoAdapter.addToList(pkgName, size, formattedSize);
- } else {
- mAppInfoAdapter.updatePackage(pkgName, size, formattedSize);
- }
- }
- break;
- case REFRESH_LABELS:
- Map labelMap = (Map) msg.obj;
- if (labelMap != null) {
- mAppInfoAdapter.bulkUpdateLabels(labelMap);
- }
- break;
- case REFRESH_ICONS:
- Map iconMap = (Map) msg.obj;
- if (iconMap != null) {
- mAppInfoAdapter.bulkUpdateIcons(iconMap);
- }
- break;
- case REFRESH_DONE:
- mLoadLabels = true;
- mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
- break;
- case NEXT_LOAD_STEP:
- if (!mCache.isEmpty() && mSetListViewLater) {
- if (localLOGV) Log.i(TAG, "Using cache to populate list view");
- initListView();
- mSetListViewLater = false;
- mFirst = true;
- }
- if (mComputeSizes && mLoadLabels) {
- doneLoadingData();
- // Check for added/removed packages
- Set keys = mAddRemoveMap.keySet();
- for (String key : keys) {
- if (mAddRemoveMap.get(key) == Boolean.TRUE) {
- // Add the package
- updatePackageList(Intent.ACTION_PACKAGE_ADDED, key);
- } else {
- // Remove the package
- updatePackageList(Intent.ACTION_PACKAGE_REMOVED, key);
- }
- }
- mAddRemoveMap.clear();
- } else if (!mComputeSizes && !mLoadLabels) {
- // Either load the package labels or initiate get size info
- if (mSizesFirst) {
- initComputeSizes();
- } else {
- initResourceThread();
- }
- } else {
- if (mSetListViewLater) {
- if (localLOGV) Log.i(TAG, "Initing list view for very first time");
- initListView();
- mSetListViewLater = false;
- }
- if (!mComputeSizes) {
- initComputeSizes();
- } else if (!mLoadLabels) {
- initResourceThread();
- }
- }
- break;
- default:
- break;
- }
- }
- };
-
- private void initListView() {
- // Create list view from the adapter here. Wait till the sort order
- // of list is defined. its either by label or by size. So atleast one of the
- // first steps should have been completed before the list gets filled.
- mAppInfoAdapter.sortBaseList(mSortOrder);
- if (mJustCreated) {
- // Set the adapter here.
- mJustCreated = false;
- mListView.setAdapter(mAppInfoAdapter);
- dismissLoadingMsg();
- }
- }
-
- class SizeObserver extends IPackageStatsObserver.Stub {
- private CountDownLatch mCount;
- PackageStats stats;
- boolean succeeded;
-
- public void invokeGetSize(String packageName, CountDownLatch count) {
- mCount = count;
- mPm.getPackageSizeInfo(packageName, this);
- }
-
- public void onGetStatsCompleted(PackageStats pStats, boolean pSucceeded) {
- succeeded = pSucceeded;
- stats = pStats;
- mCount.countDown();
- }
- }
-
- class TaskRunner extends Thread {
- private List mPkgList;
- private SizeObserver mSizeObserver;
- private static final int END_MSG = COMPUTE_END;
- private static final int SEND_PKG_SIZES = COMPUTE_BULK_SIZE;
- volatile boolean abort = false;
- static final int MSG_PKG_SIZE = 8;
-
- TaskRunner(List appList) {
- mPkgList = appList;
- mSizeObserver = new SizeObserver();
- start();
- }
-
- public void setAbort() {
- abort = true;
- }
-
- public void run() {
- long startTime;
- if (DEBUG_SIZE || DEBUG_TIME) {
- startTime = SystemClock.elapsedRealtime();
- }
- int size = mPkgList.size();
- int numMsgs = size / MSG_PKG_SIZE;
- if (size > (numMsgs * MSG_PKG_SIZE)) {
- numMsgs++;
- }
- int endi = 0;
- for (int j = 0; j < size; j += MSG_PKG_SIZE) {
- long sizes[];
- String formatted[];
- String packages[];
- endi += MSG_PKG_SIZE;
- if (endi > size) {
- endi = size;
- }
- sizes = new long[endi-j];
- formatted = new String[endi-j];
- packages = new String[endi-j];
- for (int i = j; i < endi; i++) {
- if (abort) {
- // Exit if abort has been set.
- break;
- }
- CountDownLatch count = new CountDownLatch(1);
- String packageName = mPkgList.get(i).packageName;
- mSizeObserver.invokeGetSize(packageName, count);
- try {
- count.await();
- } catch (InterruptedException e) {
- Log.i(TAG, "Failed computing size for pkg : "+packageName);
- }
- // Process the package statistics
- PackageStats pStats = mSizeObserver.stats;
- boolean succeeded = mSizeObserver.succeeded;
- long total;
- if(succeeded && pStats != null) {
- total = getTotalSize(pStats);
- } else {
- total = SIZE_INVALID;
- }
- sizes[i-j] = total;
- formatted[i-j] = getSizeStr(total).toString();
- packages[i-j] = packageName;
- }
- // Post update message
- Bundle data = new Bundle();
- data.putStringArray(ATTR_PKGS, packages);
- data.putLongArray(ATTR_STATS, sizes);
- data.putStringArray(ATTR_SIZE_STRS, formatted);
- Message msg = mHandler.obtainMessage(SEND_PKG_SIZES, data);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
- if (DEBUG_SIZE || DEBUG_TIME) Log.i(TAG, "Took "+
- (SystemClock.elapsedRealtime() - startTime)+
- " ms to compute sizes of all packages ");
- mHandler.sendEmptyMessage(END_MSG);
- }
- }
-
- /*
- * This method compares the current cache against a new list of
- * installed applications and tries to update the list with add or remove
- * messages.
- */
- private boolean updateAppList(List newList) {
- if ((newList == null) || mCache.isEmpty()) {
- return false;
- }
- Set existingList = new HashSet();
- boolean ret = false;
- // Loop over new list and find out common elements between old and new lists
- for (ApplicationInfo info : newList) {
- String pkgName = info.packageName;
- AppInfo aInfo = mCache.getEntry(pkgName);
- if (aInfo != null) {
- existingList.add(pkgName);
- } else {
- // New package. update info by refreshing
- if (localLOGV) Log.i(TAG, "New pkg :"+pkgName+" installed when paused");
- updatePackageList(Intent.ACTION_PACKAGE_ADDED, pkgName);
- ret = true;
- }
- }
- // Loop over old list and figure out state entries
- List deletedList = null;
- Set staleList = mCache.getPkgList();
- for (String pkgName : staleList) {
- if (!existingList.contains(pkgName)) {
- if (localLOGV) Log.i(TAG, "Pkg :"+pkgName+" deleted when paused");
- if (deletedList == null) {
- deletedList = new ArrayList();
- deletedList.add(pkgName);
- }
- ret = true;
- }
- }
- // Delete right away
- if (deletedList != null) {
- mAppInfoAdapter.removeFromList(deletedList);
- }
- return ret;
- }
-
- private void doneLoadingData() {
- setProgressBarIndeterminateVisibility(false);
- }
-
- List getInstalledApps(int filterOption) {
- List installedAppList = mPm.getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES);
- if (installedAppList == null) {
- return new ArrayList ();
- }
- if (filterOption == FILTER_APPS_THIRD_PARTY) {
- List appList =new ArrayList ();
- for (ApplicationInfo appInfo : installedAppList) {
- boolean flag = false;
- if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- // Updated system app
- flag = true;
- } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- // Non-system app
- flag = true;
- }
- if (flag) {
- appList.add(appInfo);
- }
- }
- return appList;
- } else if (filterOption == FILTER_APPS_RUNNING) {
- List appList =new ArrayList ();
- List procList = getRunningAppProcessesList();
- if ((procList == null) || (procList.size() == 0)) {
- return appList;
- }
- // Retrieve running processes from ActivityManager
- for (ActivityManager.RunningAppProcessInfo appProcInfo : procList) {
- if ((appProcInfo != null) && (appProcInfo.pkgList != null)){
- int size = appProcInfo.pkgList.length;
- for (int i = 0; i < size; i++) {
- ApplicationInfo appInfo = null;
- try {
- appInfo = mPm.getApplicationInfo(appProcInfo.pkgList[i],
- PackageManager.GET_UNINSTALLED_PACKAGES);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Error retrieving ApplicationInfo for pkg:"+appProcInfo.pkgList[i]);
- continue;
- }
- if(appInfo != null) {
- appList.add(appInfo);
- }
- }
- }
- }
- return appList;
- } else {
- return installedAppList;
- }
- }
-
- /*
- * Utility method used to figure out list of apps based on filterOption
- * If the framework supports an additional flag to indicate running apps
- * we can get away with some code here.
- */
- List getFilteredApps(List pAppList, int filterOption) {
- List retList = new ArrayList();
- if(pAppList == null) {
- return retList;
- }
- if (filterOption == FILTER_APPS_THIRD_PARTY) {
- List appList =new ArrayList ();
- for (ApplicationInfo appInfo : pAppList) {
- boolean flag = false;
- if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- // Updated system app
- flag = true;
- } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- // Non-system app
- flag = true;
- }
- if (flag) {
- appList.add(appInfo);
- }
- }
- return appList;
- } else if (filterOption == FILTER_APPS_RUNNING) {
- List appList =new ArrayList ();
- List procList = getRunningAppProcessesList();
- if ((procList == null) || (procList.size() == 0)) {
- return appList;
- }
- // Retrieve running processes from ActivityManager
- HashMap runningMap =
- new HashMap();
- for (ActivityManager.RunningAppProcessInfo appProcInfo : procList) {
- if ((appProcInfo != null) && (appProcInfo.pkgList != null)){
- int size = appProcInfo.pkgList.length;
- for (int i = 0; i < size; i++) {
- runningMap.put(appProcInfo.pkgList[i], appProcInfo);
- }
- }
- }
- // Query list to find running processes in current list
- for (ApplicationInfo appInfo : pAppList) {
- if (runningMap.get(appInfo.packageName) != null) {
- appList.add(appInfo);
- }
- }
- return appList;
- } else {
- return pAppList;
- }
- }
-
- private List getRunningAppProcessesList() {
- ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
- return am.getRunningAppProcesses();
- }
-
- // Some initialization code used when kicking off the size computation
- private void initAppList(List appList, int filterOption) {
- setProgressBarIndeterminateVisibility(true);
- mComputeSizes = false;
- mLoadLabels = false;
- // Initialize lists
- mAddRemoveMap = new TreeMap();
- mAppInfoAdapter.initMapFromList(appList, filterOption);
- }
-
- // Utility method to start a thread to read application labels and icons
- private void initResourceThread() {
- if ((mResourceThread != null) && mResourceThread.isAlive()) {
- mResourceThread.setAbort();
- }
- mResourceThread = new ResourceLoaderThread();
- List appList = mAppInfoAdapter.getBaseAppList();
- if ((appList != null) && (appList.size()) > 0) {
- mResourceThread.loadAllResources(appList);
- }
- }
-
- private void initComputeSizes() {
- // Initiate compute package sizes
- if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
- if ((mSizeComputor != null) && (mSizeComputor.isAlive())) {
- mSizeComputor.setAbort();
- }
- List appList = mAppInfoAdapter.getBaseAppList();
- if ((appList != null) && (appList.size()) > 0) {
- mSizeComputor = new TaskRunner(appList);
- } else {
- mComputeSizes = true;
- }
- }
-
- private void showEmptyViewIfListEmpty() {
- if (localLOGV) Log.i(TAG, "Checking for empty view");
- if (mAppInfoAdapter.getCount() > 0) {
- mListView.setVisibility(View.VISIBLE);
- mEmptyView.setVisibility(View.GONE);
- } else {
- mListView.setVisibility(View.GONE);
- mEmptyView.setVisibility(View.VISIBLE);
- }
- }
-
- // internal structure used to track added and deleted packages when
- // the activity has focus
- class AddRemoveInfo {
- String pkgName;
- boolean add;
- public AddRemoveInfo(String pPkgName, boolean pAdd) {
- pkgName = pPkgName;
- add = pAdd;
- }
- }
-
- class ResourceLoaderThread extends Thread {
- List mAppList;
- volatile boolean abort = false;
- static final int MSG_PKG_SIZE = 8;
-
- public void setAbort() {
- abort = true;
- }
- void loadAllResources(List appList) {
- mAppList = appList;
- start();
- }
-
- public void run() {
- long start;
- if (DEBUG_TIME) {
- start = SystemClock.elapsedRealtime();
- }
- int imax;
- if(mAppList == null || (imax = mAppList.size()) <= 0) {
- Log.w(TAG, "Empty or null application list");
- } else {
- int size = mAppList.size();
- int numMsgs = size / MSG_PKG_SIZE;
- if (size > (numMsgs * MSG_PKG_SIZE)) {
- numMsgs++;
- }
- int endi = 0;
- for (int j = 0; j < size; j += MSG_PKG_SIZE) {
- Map map = new HashMap();
- endi += MSG_PKG_SIZE;
- if (endi > size) {
- endi = size;
- }
- for (int i = j; i < endi; i++) {
- if (abort) {
- // Exit if abort has been set.
- break;
- }
- ApplicationInfo appInfo = mAppList.get(i);
- map.put(appInfo.packageName, appInfo.loadLabel(mPm));
- }
- // Post update message
- Message msg = mHandler.obtainMessage(REFRESH_LABELS);
- msg.obj = map;
- mHandler.sendMessage(msg);
- }
- Message doneMsg = mHandler.obtainMessage(REFRESH_DONE);
- mHandler.sendMessage(doneMsg);
- if (DEBUG_TIME) Log.i(TAG, "Took "+(SystemClock.elapsedRealtime()-start)+
- " ms to load app labels");
- long startIcons;
- if (DEBUG_TIME) {
- startIcons = SystemClock.elapsedRealtime();
- }
- Map map = new HashMap();
- for (int i = (imax-1); i >= 0; i--) {
- if (abort) {
- return;
- }
- ApplicationInfo appInfo = mAppList.get(i);
- map.put(appInfo.packageName, appInfo.loadIcon(mPm));
- }
- Message msg = mHandler.obtainMessage(REFRESH_ICONS);
- msg.obj = map;
- mHandler.sendMessage(msg);
- if (DEBUG_TIME) Log.i(TAG, "Took "+(SystemClock.elapsedRealtime()-startIcons)+" ms to load app icons");
- }
- if (DEBUG_TIME) Log.i(TAG, "Took "+(SystemClock.elapsedRealtime()-start)+" ms to load app resources");
- }
- }
-
- /* Internal class representing an application or packages displayable attributes
- *
- */
- class AppInfo {
- public String pkgName;
- int index;
- public CharSequence appName;
- public Drawable appIcon;
- public CharSequence appSize;
- long size;
-
- public void refreshIcon(Drawable icon) {
- if (icon == null) {
- return;
- }
- appIcon = icon;
- }
- public void refreshLabel(CharSequence label) {
- if (label == null) {
- return;
- }
- appName = label;
- }
-
- public AppInfo(String pName, int pIndex, CharSequence aName,
- long pSize,
- CharSequence pSizeStr) {
- this(pName, pIndex, aName, mDefaultAppIcon, pSize, pSizeStr);
- }
-
- public AppInfo(String pName, int pIndex, CharSequence aName, Drawable aIcon,
- long pSize,
- CharSequence pSizeStr) {
- index = pIndex;
- pkgName = pName;
- appName = aName;
- appIcon = aIcon;
- size = pSize;
- appSize = pSizeStr;
- }
-
- public boolean setSize(long newSize, String formattedSize) {
- if (size != newSize) {
- size = newSize;
- appSize = formattedSize;
- return true;
- }
- return false;
- }
- }
-
- private long getTotalSize(PackageStats ps) {
- if (ps != null) {
- return ps.cacheSize+ps.codeSize+ps.dataSize;
- }
- return SIZE_INVALID;
- }
-
- private CharSequence getSizeStr(long size) {
- CharSequence appSize = null;
- if (size == SIZE_INVALID) {
- return mInvalidSizeStr;
- }
- appSize = Formatter.formatFileSize(ManageApplications.this, size);
- return appSize;
- }
-
- // View Holder used when displaying views
- static class AppViewHolder {
- TextView appName;
- ImageView appIcon;
- TextView appSize;
- }
-
- /*
- * Custom adapter implementation for the ListView
- * This adapter maintains a map for each displayed application and its properties
- * An index value on each AppInfo object indicates the correct position or index
- * in the list. If the list gets updated dynamically when the user is viewing the list of
- * applications, we need to return the correct index of position. This is done by mapping
- * the getId methods via the package name into the internal maps and indices.
- * The order of applications in the list is mirrored in mAppLocalList
- */
- class AppInfoAdapter extends BaseAdapter {
- private List mAppList;
- private List mAppLocalList;
- AlphaComparator mAlphaComparator = new AlphaComparator();
- SizeComparator mSizeComparator = new SizeComparator();
-
- // Make sure the cache or map contains entries for all elements
- // in appList for a valid sort.
- public void initMapFromList(List pAppList, int filterOption) {
- boolean notify = false;
- List appList = null;
- if (pAppList == null) {
- // Just refresh the list
- appList = mAppList;
- } else {
- mAppList = pAppList;
- appList = pAppList;
- notify = true;
- }
- mAppLocalList = getFilteredApps(appList, filterOption);
- // This loop verifies and creates new entries for new packages in list
- int imax = appList.size();
- for (int i = 0; i < imax; i++) {
- ApplicationInfo info = appList.get(i);
- AppInfo aInfo = mCache.getEntry(info.packageName);
- if(aInfo == null){
- aInfo = new AppInfo(info.packageName, i,
- info.packageName, -1, mComputingSizeStr);
- if (localLOGV) Log.i(TAG, "Creating entry pkg:"+info.packageName+" to map");
- mCache.addEntry(aInfo);
- }
- }
- sortListInner(mSortOrder);
- if (notify) {
- notifyDataSetChanged();
- }
- }
-
- public AppInfoAdapter(Context c, List appList) {
- mAppList = appList;
- }
-
- public int getCount() {
- return mAppLocalList.size();
- }
-
- public Object getItem(int position) {
- return mAppLocalList.get(position);
- }
-
- /*
- * This method returns the index of the package position in the application list
- */
- public int getIndex(String pkgName) {
- if(pkgName == null) {
- Log.w(TAG, "Getting index of null package in List Adapter");
- }
- int imax = mAppLocalList.size();
- ApplicationInfo appInfo;
- for(int i = 0; i < imax; i++) {
- appInfo = mAppLocalList.get(i);
- if(appInfo.packageName.equalsIgnoreCase(pkgName)) {
- return i;
- }
- }
- return -1;
- }
-
- public ApplicationInfo getApplicationInfo(int position) {
- int imax = mAppLocalList.size();
- if( (position < 0) || (position >= imax)) {
- Log.w(TAG, "Position out of bounds in List Adapter");
- return null;
- }
- return mAppLocalList.get(position);
- }
-
- public long getItemId(int position) {
- int imax = mAppLocalList.size();
- if( (position < 0) || (position >= imax)) {
- Log.w(TAG, "Position out of bounds in List Adapter");
- return -1;
- }
- AppInfo aInfo = mCache.getEntry(mAppLocalList.get(position).packageName);
- if (aInfo == null) {
- return -1;
- }
- return aInfo.index;
- }
-
- public List getBaseAppList() {
- return mAppList;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- if (position >= mAppLocalList.size()) {
- Log.w(TAG, "Invalid view position:"+position+", actual size is:"+mAppLocalList.size());
- return null;
- }
- // A ViewHolder keeps references to children views to avoid unneccessary calls
- // to findViewById() on each row.
- AppViewHolder holder;
-
- // When convertView is not null, we can reuse it directly, there is no need
- // to reinflate it. We only inflate a new View when the convertView supplied
- // by ListView is null.
- if (convertView == null) {
- convertView = mInflater.inflate(R.layout.manage_applications_item, null);
-
- // Creates a ViewHolder and store references to the two children views
- // we want to bind data to.
- holder = new AppViewHolder();
- holder.appName = (TextView) convertView.findViewById(R.id.app_name);
- holder.appIcon = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.appSize = (TextView) convertView.findViewById(R.id.app_size);
- convertView.setTag(holder);
- } else {
- // Get the ViewHolder back to get fast access to the TextView
- // and the ImageView.
- holder = (AppViewHolder) convertView.getTag();
- }
-
- // Bind the data efficiently with the holder
- ApplicationInfo appInfo = mAppLocalList.get(position);
- AppInfo mInfo = mCache.getEntry(appInfo.packageName);
- if(mInfo != null) {
- if(mInfo.appName != null) {
- holder.appName.setText(mInfo.appName);
- }
- if(mInfo.appIcon != null) {
- holder.appIcon.setImageDrawable(mInfo.appIcon);
- }
- if (mInfo.appSize != null) {
- holder.appSize.setText(mInfo.appSize);
- }
- } else {
- Log.w(TAG, "No info for package:"+appInfo.packageName+" in property map");
- }
- return convertView;
- }
-
- private void adjustIndex() {
- int imax = mAppLocalList.size();
- for (int i = 0; i < imax; i++) {
- ApplicationInfo info = mAppLocalList.get(i);
- mCache.getEntry(info.packageName).index = i;
- }
- }
-
- public void sortAppList(List appList, int sortOrder) {
- Collections.sort(appList, getAppComparator(sortOrder));
- }
-
- public void sortBaseList(int sortOrder) {
- if (localLOGV) Log.i(TAG, "Sorting base list based on sortOrder = "+sortOrder);
- sortAppList(mAppList, sortOrder);
- mAppLocalList = getFilteredApps(mAppList, mFilterApps);
- adjustIndex();
- }
-
- private void sortListInner(int sortOrder) {
- sortAppList(mAppLocalList, sortOrder);
- adjustIndex();
- }
-
- public void sortList(int sortOrder) {
- if (localLOGV) Log.i(TAG, "sortOrder = "+sortOrder);
- sortListInner(sortOrder);
- notifyDataSetChanged();
- }
-
- /*
- * Reset the application list associated with this adapter.
- * @param filterOption Sort the list based on this value
- * @param appList the actual application list that is used to reset
- * @return Return a boolean value to indicate inconsistency
- */
- public boolean resetAppList(int filterOption) {
- // Change application list based on filter option
- mAppLocalList = getFilteredApps(mAppList, filterOption);
- // Check for all properties in map before sorting. Populate values from cache
- for(ApplicationInfo applicationInfo : mAppLocalList) {
- AppInfo appInfo = mCache.getEntry(applicationInfo.packageName);
- if(appInfo == null) {
- Log.i(TAG, " Entry does not exist for pkg: " + applicationInfo.packageName);
- }
- }
- if (mAppLocalList.size() > 0) {
- sortList(mSortOrder);
- } else {
- notifyDataSetChanged();
- }
- showEmptyViewIfListEmpty();
- return true;
- }
-
- private Comparator getAppComparator(int sortOrder) {
- if (sortOrder == SORT_ORDER_ALPHA) {
- return mAlphaComparator;
- }
- return mSizeComparator;
- }
-
- public void bulkUpdateIcons(Map icons) {
- if (icons == null) {
- return;
- }
- Set keys = icons.keySet();
- boolean changed = false;
- for (String key : keys) {
- Drawable ic = icons.get(key);
- if (ic != null) {
- AppInfo aInfo = mCache.getEntry(key);
- if (aInfo != null) {
- aInfo.refreshIcon(ic);
- changed = true;
- }
- }
- }
- if (changed) {
- notifyDataSetChanged();
- }
- }
-
- public void bulkUpdateLabels(Map map) {
- if (map == null) {
- return;
- }
- Set keys = map.keySet();
- boolean changed = false;
- for (String key : keys) {
- CharSequence label = map.get(key);
- AppInfo aInfo = mCache.getEntry(key);
- if (aInfo != null) {
- aInfo.refreshLabel(label);
- changed = true;
- }
- }
- if (changed) {
- notifyDataSetChanged();
- }
- }
-
- private boolean shouldBeInList(int filterOption, ApplicationInfo info) {
- // Match filter here
- if (filterOption == FILTER_APPS_RUNNING) {
- List runningList = getInstalledApps(FILTER_APPS_RUNNING);
- for (ApplicationInfo running : runningList) {
- if (running.packageName.equalsIgnoreCase(info.packageName)) {
- return true;
- }
- }
- } else if (filterOption == FILTER_APPS_THIRD_PARTY) {
- if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- return true;
- } else if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- return true;
- }
- } else {
- return true;
- }
- return false;
- }
-
- /*
- * Add a package to the current list.
- * The package is only added to the displayed list
- * based on the filter value. The package is always added to the property map.
- * @param pkgName name of package to be added
- * @param ps PackageStats of new package
- */
- public void addToList(String pkgName, long size, String formattedSize) {
- if (pkgName == null) {
- return;
- }
- boolean notInList = true;
- // Get ApplicationInfo
- ApplicationInfo info = null;
- try {
- info = mPm.getApplicationInfo(pkgName, 0);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Ignoring non-existent package:"+pkgName);
- return;
- }
- if(info == null) {
- // Nothing to do log error message and return
- Log.i(TAG, "Null ApplicationInfo for package:"+pkgName);
- return;
- }
- // Add entry to local list
- mAppList.add(info);
- // Add entry to map. Note that the index gets adjusted later on based on
- // whether the newly added package is part of displayed list
- mCache.addEntry(new AppInfo(pkgName, -1,
- info.loadLabel(mPm), info.loadIcon(mPm), size, formattedSize));
- // Add to list
- if (notInList && (shouldBeInList(mFilterApps, info))) {
- // Binary search returns a negative index (ie -index) of the position where
- // this might be inserted.
- int newIdx = Collections.binarySearch(mAppLocalList, info,
- getAppComparator(mSortOrder));
- if(newIdx >= 0) {
- Log.i(TAG, "Strange. Package:"+pkgName+" is not new");
- return;
- }
- // New entry
- newIdx = -newIdx-1;
- mAppLocalList.add(newIdx, info);
- // Adjust index
- adjustIndex();
- notifyDataSetChanged();
- }
- }
-
- public void updatePackage(String pkgName,
- long size, String formattedSize) {
- ApplicationInfo info = null;
- try {
- info = mPm.getApplicationInfo(pkgName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
- } catch (NameNotFoundException e) {
- return;
- }
- AppInfo aInfo = mCache.getEntry(pkgName);
- if (aInfo != null) {
- aInfo.refreshLabel(info.loadLabel(mPm));
- aInfo.refreshIcon(info.loadIcon(mPm));
- aInfo.setSize(size, formattedSize);
- notifyDataSetChanged();
- }
- }
-
- private void removePkgBase(String pkgName) {
- int imax = mAppList.size();
- for (int i = 0; i < imax; i++) {
- ApplicationInfo app = mAppList.get(i);
- if (app.packageName.equalsIgnoreCase(pkgName)) {
- if (localLOGV) Log.i(TAG, "Removing pkg: "+pkgName+" from base list");
- mAppList.remove(i);
- return;
- }
- }
- }
-
- public void removeFromList(List pkgNames) {
- if(pkgNames == null) {
- return;
- }
- if(pkgNames.size() <= 0) {
- return;
- }
- boolean found = false;
- for (String pkg : pkgNames) {
- // Remove from the base application list
- removePkgBase(pkg);
- // Remove from cache
- if (localLOGV) Log.i(TAG, "Removing " + pkg + " from cache");
- mCache.removeEntry(pkg);
- // Remove from filtered list
- int i = 0;
- for (ApplicationInfo info : mAppLocalList) {
- if (info.packageName.equalsIgnoreCase(pkg)) {
- mAppLocalList.remove(i);
- if (localLOGV) Log.i(TAG, "Removing " + pkg + " from local list");
- found = true;
- break;
- }
- i++;
- }
- }
- // Adjust indices of list entries
- if (found) {
- adjustIndex();
- if (localLOGV) Log.i(TAG, "adjusting index and notifying list view");
- notifyDataSetChanged();
- }
- }
-
- public void bulkUpdateSizes(String pkgs[], long sizes[], String formatted[]) {
- if(pkgs == null || sizes == null || formatted == null) {
- return;
- }
- boolean changed = false;
- for (int i = 0; i < pkgs.length; i++) {
- AppInfo entry = mCache.getEntry(pkgs[i]);
- if (entry == null) {
- if (localLOGV) Log.w(TAG, "Entry for package:"+ pkgs[i] +"doesn't exist in map");
- continue;
- }
- if (entry.setSize(sizes[i], formatted[i])) {
- changed = true;
- }
- }
- if (changed) {
- notifyDataSetChanged();
- }
- }
- }
-
- /*
- * Utility method to clear messages to Handler
- * We need'nt synchronize on the Handler since posting messages is guaranteed
- * to be thread safe. Even if the other thread that retrieves package sizes
- * posts a message, we do a cursory check of validity on mAppInfoAdapter's applist
- */
- private void clearMessagesInHandler() {
- mHandler.removeMessages(INIT_PKG_INFO);
- mHandler.removeMessages(COMPUTE_BULK_SIZE);
- mHandler.removeMessages(REMOVE_PKG);
- mHandler.removeMessages(REORDER_LIST);
- mHandler.removeMessages(ADD_PKG_START);
- mHandler.removeMessages(ADD_PKG_DONE);
- mHandler.removeMessages(REFRESH_LABELS);
- mHandler.removeMessages(REFRESH_DONE);
- mHandler.removeMessages(NEXT_LOAD_STEP);
- mHandler.removeMessages(COMPUTE_END);
- }
-
- private void sendMessageToHandler(int msgId, int arg1) {
- Message msg = mHandler.obtainMessage(msgId);
- msg.arg1 = arg1;
- mHandler.sendMessage(msg);
- }
-
- private void sendMessageToHandler(int msgId, Bundle data) {
- Message msg = mHandler.obtainMessage(msgId);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
-
- private void sendMessageToHandler(int msgId) {
- mHandler.sendEmptyMessage(msgId);
- }
-
- /*
- * Stats Observer class used to compute package sizes and retrieve size information
- * PkgSizeOberver is the call back thats used when invoking getPackageSizeInfo on
- * PackageManager. The values in call back onGetStatsCompleted are validated
- * and the specified message is passed to mHandler. The package name
- * and the AppInfo object corresponding to the package name are set on the message
- */
- class PkgSizeObserver extends IPackageStatsObserver.Stub {
- String pkgName;
- public void onGetStatsCompleted(PackageStats pStats, boolean pSucceeded) {
- if(DEBUG_PKG_DELAY) {
- try {
- Thread.sleep(10*1000);
- } catch (InterruptedException e) {
- }
- }
- Bundle data = new Bundle();
- data.putString(ATTR_PKG_NAME, pkgName);
- data.putBoolean(ATTR_GET_SIZE_STATUS, pSucceeded);
- if(pSucceeded && pStats != null) {
- if (localLOGV) Log.i(TAG, "onGetStatsCompleted::"+pkgName+", ("+
- pStats.cacheSize+","+
- pStats.codeSize+", "+pStats.dataSize);
- long total = getTotalSize(pStats);
- data.putLong(ATTR_PKG_STATS, total);
- CharSequence sizeStr = getSizeStr(total);
- data.putString(ATTR_PKG_SIZE_STR, sizeStr.toString());
- } else {
- Log.w(TAG, "Invalid package stats from PackageManager");
- }
- // Post message to Handler
- Message msg = mHandler.obtainMessage(ADD_PKG_DONE, data);
- msg.setData(data);
- mHandler.sendMessage(msg);
- }
-
- public void invokeGetSizeInfo(String packageName) {
- if (packageName == null) {
- return;
- }
- pkgName = packageName;
- if(localLOGV) Log.i(TAG, "Invoking getPackageSizeInfo for package:"+
- packageName);
- mPm.getPackageSizeInfo(packageName, this);
- }
- }
-
- /**
- * Receives notifications when applications are added/removed.
- */
- private class PackageIntentReceiver extends BroadcastReceiver {
- void registerReceiver() {
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- ManageApplications.this.registerReceiver(this, filter);
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- String actionStr = intent.getAction();
- Uri data = intent.getData();
- String pkgName = data.getEncodedSchemeSpecificPart();
- if (localLOGV) Log.i(TAG, "action:"+actionStr+", for package:"+pkgName);
- updatePackageList(actionStr, pkgName);
- }
- }
-
- private void updatePackageList(String actionStr, String pkgName) {
- // technically we dont have to invoke handler since onReceive is invoked on
- // the main thread but doing it here for better clarity
- if (Intent.ACTION_PACKAGE_ADDED.equalsIgnoreCase(actionStr)) {
- Bundle data = new Bundle();
- data.putString(ATTR_PKG_NAME, pkgName);
- sendMessageToHandler(ADD_PKG_START, data);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equalsIgnoreCase(actionStr)) {
- Bundle data = new Bundle();
- data.putString(ATTR_PKG_NAME, pkgName);
- sendMessageToHandler(REMOVE_PKG, data);
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if(localLOGV) Log.i(TAG, "Activity created");
- long sCreate;
- if (DEBUG_TIME) {
- sCreate = SystemClock.elapsedRealtime();
- }
- Intent intent = getIntent();
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_MANAGE_PACKAGE_STORAGE)) {
- mSortOrder = SORT_ORDER_SIZE;
- mSizesFirst = true;
- }
- mPm = getPackageManager();
- // initialize some window features
- requestWindowFeature(Window.FEATURE_RIGHT_ICON);
- requestWindowFeature(Window.FEATURE_PROGRESS);
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.compute_sizes);
- showLoadingMsg();
- mDefaultAppIcon =Resources.getSystem().getDrawable(
- com.android.internal.R.drawable.sym_def_app_icon);
- mInvalidSizeStr = getText(R.string.invalid_size_value);
- mComputingSizeStr = getText(R.string.computing_size);
- // initialize the inflater
- mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mReceiver = new PackageIntentReceiver();
- mEmptyView = (TextView) findViewById(R.id.empty_view);
- mObserver = new PkgSizeObserver();
- // Create adapter and list view here
- List appList = getInstalledApps(mSortOrder);
- mAppInfoAdapter = new AppInfoAdapter(this, appList);
- ListView lv= (ListView) findViewById(android.R.id.list);
- lv.setOnItemClickListener(this);
- lv.setSaveEnabled(true);
- lv.setItemsCanFocus(true);
- lv.setOnItemClickListener(this);
- mListView = lv;
- if (DEBUG_TIME) {
- Log.i(TAG, "Total time in Activity.create:: " +
- (SystemClock.elapsedRealtime() - sCreate)+ " ms");
- }
- // Get initial info from file for the very first time this activity started
- long sStart;
- if (DEBUG_TIME) {
- sStart = SystemClock.elapsedRealtime();
- }
- mCache.loadCache();
- if (DEBUG_TIME) {
- Log.i(TAG, "Took " + (SystemClock.elapsedRealtime()-sStart) + " ms to init cache");
- }
- }
-
- protected void onDestroy() {
- // Persist values in cache
- mCache.updateCache();
- super.onDestroy();
- }
-
- @Override
- public Dialog onCreateDialog(int id) {
- if (id == DLG_LOADING) {
- ProgressDialog dlg = new ProgressDialog(this);
- dlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
- dlg.setMessage(getText(R.string.loading));
- dlg.setIndeterminate(true);
- dlg.setOnCancelListener(this);
- return dlg;
- }
- return null;
- }
-
- private void showLoadingMsg() {
- if (DEBUG_TIME) {
- mLoadTimeStart = SystemClock.elapsedRealtime();
- }
- showDialog(DLG_LOADING);
- if(localLOGV) Log.i(TAG, "Displaying Loading message");
- }
-
- private void dismissLoadingMsg() {
- if(localLOGV) Log.i(TAG, "Dismissing Loading message");
- dismissDialog(DLG_LOADING);
- if (DEBUG_TIME) Log.i(TAG, "Displayed loading message for "+
- (SystemClock.elapsedRealtime() - mLoadTimeStart) + " ms");
- }
-
- class AppInfoCache {
- final static boolean FILE_CACHE = true;
- private static final String mFileCacheName="ManageAppsInfo.txt";
- private static final int FILE_BUFFER_SIZE = 1024;
- private static final boolean DEBUG_CACHE = false;
- private static final boolean DEBUG_CACHE_TIME = false;
- private Map mAppPropCache = new HashMap();
-
- private boolean isEmpty() {
- return (mAppPropCache.size() == 0);
- }
-
- private AppInfo getEntry(String pkgName) {
- return mAppPropCache.get(pkgName);
- }
-
- private Set getPkgList() {
- return mAppPropCache.keySet();
- }
-
- public void addEntry(AppInfo aInfo) {
- if ((aInfo != null) && (aInfo.pkgName != null)) {
- mAppPropCache.put(aInfo.pkgName, aInfo);
- }
- }
-
- public void removeEntry(String pkgName) {
- if (pkgName != null) {
- mAppPropCache.remove(pkgName);
- }
- }
-
- private void readFromFile() {
- File cacheFile = new File(getFilesDir(), mFileCacheName);
- if (!cacheFile.exists()) {
- return;
- }
- FileInputStream fis = null;
- boolean err = false;
- try {
- fis = new FileInputStream(cacheFile);
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Error opening file for read operation : " + cacheFile
- + " with exception " + e);
- return;
- }
- try {
- byte[] byteBuff = new byte[FILE_BUFFER_SIZE];
- byte[] lenBytes = new byte[2];
- mAppPropCache.clear();
- while(fis.available() > 0) {
- fis.read(lenBytes, 0, 2);
- int buffLen = (lenBytes[0] << 8) | lenBytes[1];
- if ((buffLen <= 0) || (buffLen > byteBuff.length)) {
- err = true;
- break;
- }
- // Buffer length cannot be great then max.
- fis.read(byteBuff, 0, buffLen);
- String buffStr = new String(byteBuff);
- if (DEBUG_CACHE) {
- Log.i(TAG, "Read string of len= " + buffLen + " :: " + buffStr + " from file");
- }
- // Parse string for sizes
- String substrs[] = buffStr.split(",");
- if (substrs.length < 4) {
- // Something wrong. Bail out and let recomputation proceed.
- err = true;
- break;
- }
- long size = -1;
- int idx = -1;
- try {
- size = Long.parseLong(substrs[1]);
- } catch (NumberFormatException e) {
- err = true;
- break;
- }
- if (DEBUG_CACHE) {
- Log.i(TAG, "Creating entry(" + substrs[0] + ", " + idx+"," + size + ", " + substrs[2] + ")");
- }
- AppInfo aInfo = new AppInfo(substrs[0], idx, substrs[3], size, substrs[2]);
- mAppPropCache.put(aInfo.pkgName, aInfo);
- }
- } catch (IOException e) {
- Log.w(TAG, "Failed reading from file : " + cacheFile + " with exception : " + e);
- err = true;
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- Log.w(TAG, "Failed to close file " + cacheFile + " with exception : " +e);
- err = true;
- }
- }
- if (err) {
- Log.i(TAG, "Failed to load cache. Not using cache for now.");
- // Clear cache and bail out
- mAppPropCache.clear();
- }
- }
- }
-
- boolean writeToFile() {
- File cacheFile = new File(getFilesDir(), mFileCacheName);
- FileOutputStream fos = null;
- try {
- long opStartTime = SystemClock.uptimeMillis();
- fos = new FileOutputStream(cacheFile);
- Set keys = mAppPropCache.keySet();
- byte[] lenBytes = new byte[2];
- for (String key : keys) {
- AppInfo aInfo = mAppPropCache.get(key);
- StringBuilder buff = new StringBuilder(aInfo.pkgName);
- buff.append(",");
- buff.append(aInfo.size);
- buff.append(",");
- buff.append(aInfo.appSize);
- buff.append(",");
- buff.append(aInfo.appName);
- if (DEBUG_CACHE) {
- Log.i(TAG, "Writing str : " + buff.toString() + " to file of length:" +
- buff.toString().length());
- }
- try {
- byte[] byteBuff = buff.toString().getBytes();
- int len = byteBuff.length;
- if (byteBuff.length >= FILE_BUFFER_SIZE) {
- // Truncate the output
- len = FILE_BUFFER_SIZE;
- }
- // Use 2 bytes to write length
- lenBytes[1] = (byte) (len & 0x00ff);
- lenBytes[0] = (byte) ((len & 0x00ff00) >> 8);
- fos.write(lenBytes, 0, 2);
- fos.write(byteBuff, 0, len);
- } catch (IOException e) {
- Log.w(TAG, "Failed to write to file : " + cacheFile + " with exception : " + e);
- return false;
- }
- }
- if (DEBUG_CACHE_TIME) {
- Log.i(TAG, "Took " + (SystemClock.uptimeMillis() - opStartTime) + " ms to write and process from file");
- }
- return true;
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Error opening file for write operation : " + cacheFile+
- " with exception : " + e);
- return false;
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {
- Log.w(TAG, "Failed closing file : " + cacheFile + " with exception : " + e);
- return false;
- }
- }
- }
- }
- private void loadCache() {
- // Restore preferences
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- boolean disable = settings.getBoolean(PREF_DISABLE_CACHE, true);
- if (disable) Log.w(TAG, "Cache has been disabled");
- // Disable cache till the data is loaded successfully
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean(PREF_DISABLE_CACHE, true);
- editor.commit();
- if (FILE_CACHE && !disable) {
- readFromFile();
- // Enable cache since the file has been read successfully
- editor.putBoolean(PREF_DISABLE_CACHE, false);
- editor.commit();
- }
- }
-
- private void updateCache() {
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean(PREF_DISABLE_CACHE, true);
- editor.commit();
- if (FILE_CACHE) {
- boolean writeStatus = writeToFile();
- mAppPropCache.clear();
- if (writeStatus) {
- // Enable cache since the file has been read successfully
- editor.putBoolean(PREF_DISABLE_CACHE, false);
- editor.commit();
- }
- }
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- // Register receiver
- mReceiver.registerReceiver();
- sendMessageToHandler(INIT_PKG_INFO);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- // Stop the background threads
- if (mResourceThread != null) {
- mResourceThread.setAbort();
- }
- if (mSizeComputor != null) {
- mSizeComputor.setAbort();
- }
- // clear all messages related to application list
- clearMessagesInHandler();
- // register receiver here
- unregisterReceiver(mReceiver);
- }
-
- // Avoid the restart and pause when orientation changes
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- }
-
- /*
- * comparator class used to sort AppInfo objects based on size
- */
- class SizeComparator implements Comparator {
- public final int compare(ApplicationInfo a, ApplicationInfo b) {
- AppInfo ainfo = mCache.getEntry(a.packageName);
- AppInfo binfo = mCache.getEntry(b.packageName);
- long atotal = ainfo.size;
- long btotal = binfo.size;
- long ret = atotal - btotal;
- // negate result to sort in descending order
- if (ret < 0) {
- return 1;
- }
- if (ret == 0) {
- return 0;
- }
- return -1;
- }
- }
-
- /*
- * Customized comparator class to compare labels.
- * Don't use the one defined in ApplicationInfo since that loads the labels again.
- */
- class AlphaComparator implements Comparator {
- private final Collator sCollator = Collator.getInstance();
-
- public final int compare(ApplicationInfo a, ApplicationInfo b) {
- AppInfo ainfo = mCache.getEntry(a.packageName);
- AppInfo binfo = mCache.getEntry(b.packageName);
- return sCollator.compare(ainfo.appName.toString(), binfo.appName.toString());
- }
- }
-
- // utility method used to start sub activity
- private void startApplicationDetailsActivity() {
- // Create intent to start new activity
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(this, InstalledAppDetails.class);
- intent.putExtra(APP_PKG_NAME, mCurrentPkgName);
- // start new activity to display extended information
- startActivityForResult(intent, INSTALLED_APP_DETAILS);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, SORT_ORDER_ALPHA, 1, R.string.sort_order_alpha)
- .setIcon(android.R.drawable.ic_menu_sort_alphabetically);
- menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
- .setIcon(android.R.drawable.ic_menu_sort_by_size);
- menu.add(0, FILTER_OPTIONS, 3, R.string.filter)
- .setIcon(R.drawable.ic_menu_filter_settings);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if (mFirst) {
- menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
- menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
- menu.findItem(FILTER_OPTIONS).setVisible(true);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int menuId = item.getItemId();
- if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
- sendMessageToHandler(REORDER_LIST, menuId);
- } else if (menuId == FILTER_OPTIONS) {
- if (mAlertDlg == null) {
- mAlertDlg = new AlertDialog.Builder(this).
- setTitle(R.string.filter_dlg_title).
- setNeutralButton(R.string.cancel, this).
- setSingleChoiceItems(new CharSequence[] {getText(R.string.filter_apps_all),
- getText(R.string.filter_apps_running),
- getText(R.string.filter_apps_third_party)},
- -1, this).
- create();
- }
- mAlertDlg.show();
- }
- return true;
- }
-
- public void onItemClick(AdapterView> parent, View view, int position,
- long id) {
- ApplicationInfo info = (ApplicationInfo)mAppInfoAdapter.getItem(position);
- mCurrentPkgName = info.packageName;
- startApplicationDetailsActivity();
- }
-
- // Finish the activity if the user presses the back button to cancel the activity
- public void onCancel(DialogInterface dialog) {
- finish();
- }
-
- public void onClick(DialogInterface dialog, int which) {
- int newOption;
- switch (which) {
- // Make sure that values of 0, 1, 2 match options all, running, third_party when
- // created via the AlertDialog.Builder
- case 0:
- newOption = FILTER_APPS_ALL;
- break;
- case 1:
- newOption = FILTER_APPS_RUNNING;
- break;
- case 2:
- newOption = FILTER_APPS_THIRD_PARTY;
- break;
- default:
- return;
- }
- mAlertDlg.dismiss();
- sendMessageToHandler(REORDER_LIST, newOption);
- }
-}
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 38ad6081850..e653d90b375 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -16,21 +16,16 @@
package com.android.settings;
+import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.widget.LockPatternUtils;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.os.ICheckinService;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.text.TextUtils;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import android.widget.CheckBox;
/**
* Confirm and execute a reset of the device to a clean "just out of the box"
@@ -49,65 +44,45 @@ public class MasterClear extends Activity {
private View mInitialView;
private Button mInitiateButton;
+ private View mExternalStorageContainer;
+ private CheckBox mExternalStorage;
private View mFinalView;
private Button mFinalButton;
- /**
+ /**
* The user has gone through the multiple confirmation, so now we go ahead
* and invoke the Checkin Service to reset the device to its factory-default
* state (rebooting in the process).
*/
private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
public void onClick(View v) {
-
- // Those monkeys kept committing suicide, so we add this property
- // to disable going through with the master clear
- if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) {
+ if (Utils.isMonkeyRunning()) {
return;
}
-
- ICheckinService service =
- ICheckinService.Stub.asInterface(ServiceManager.getService("checkin"));
- if (service != null) {
- try {
- // This RPC should never return
- service.masterClear();
- } catch (android.os.RemoteException e) {
- // Intentionally blank - there's nothing we can do here
- Log.w("MasterClear", "Unable to invoke ICheckinService.masterClear()");
- }
+
+ if (mExternalStorage.isChecked()) {
+ Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
+ intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+ startService(intent);
} else {
- Log.w("MasterClear", "Unable to locate ICheckinService");
+ sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
+ // Intent handling is asynchronous -- assume it will happen soon.
}
-
- /* If we reach this point, the master clear didn't happen -- the
- * service might have been unregistered with the ServiceManager,
- * the RPC might have thrown an exception, or for some reason
- * the implementation of masterClear() may have returned instead
- * of resetting the device.
- */
- new AlertDialog.Builder(MasterClear.this)
- .setMessage(getText(R.string.master_clear_failed))
- .setPositiveButton(getText(android.R.string.ok), null)
- .show();
}
};
/**
- * Keyguard validation is run using the standard {@link ConfirmLockPattern}
+ * Keyguard validation is run using the standard {@link ConfirmLockPattern}
* component as a subactivity
+ * @param request the request code to be returned once confirmation finishes
+ * @return true if confirmation launched
*/
- private void runKeyguardConfirmation() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ConfirmLockPattern");
- // supply header and footer text in the intent
- intent.putExtra(ConfirmLockPattern.HEADER_TEXT,
- getText(R.string.master_clear_gesture_prompt));
- intent.putExtra(ConfirmLockPattern.FOOTER_TEXT,
- getText(R.string.master_clear_gesture_explanation));
- startActivityForResult(intent, KEYGUARD_REQUEST);
+ private boolean runKeyguardConfirmation(int request) {
+ return new ChooseLockSettingsHelper(this)
+ .launchConfirmationActivity(request,
+ getText(R.string.master_clear_gesture_prompt),
+ getText(R.string.master_clear_gesture_explanation));
}
@Override
@@ -122,6 +97,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK) {
establishFinalConfirmationState();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ finish();
} else {
establishInitialState();
}
@@ -134,9 +111,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
*/
private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
public void onClick(View v) {
- if (mLockUtils.isLockPatternEnabled()) {
- runKeyguardConfirmation();
- } else {
+ if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
establishFinalConfirmationState();
}
}
@@ -161,7 +136,7 @@ private void establishFinalConfirmationState() {
* click in order to initiate a confirmation sequence. This method is
* called from various other points in the code to reset the activity to
* this base state.
- *
+ *
* Reinflating views from resources is expensive and prevents us from
* caching widget pointers, so we use a single-inflate pattern: we lazy-
* inflate each view, caching all of the widget pointers we'll need at the
@@ -174,6 +149,16 @@ private void establishInitialState() {
mInitiateButton =
(Button) mInitialView.findViewById(R.id.initiate_master_clear);
mInitiateButton.setOnClickListener(mInitiateListener);
+ mExternalStorageContainer =
+ mInitialView.findViewById(R.id.erase_external_container);
+ mExternalStorage =
+ (CheckBox) mInitialView.findViewById(R.id.erase_external);
+ mExternalStorageContainer.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mExternalStorage.toggle();
+ }
+ });
}
setContentView(mInitialView);
@@ -186,7 +171,7 @@ protected void onCreate(Bundle savedState) {
mInitialView = null;
mFinalView = null;
mInflater = LayoutInflater.from(this);
- mLockUtils = new LockPatternUtils(getContentResolver());
+ mLockUtils = new LockPatternUtils(this);
establishInitialState();
}
@@ -199,7 +184,8 @@ protected void onCreate(Bundle savedState) {
public void onPause() {
super.onPause();
- establishInitialState();
+ if (!isFinishing()) {
+ establishInitialState();
+ }
}
-
}
diff --git a/src/com/android/settings/MediaFormat.java b/src/com/android/settings/MediaFormat.java
index 3594572a927..cc780c990fe 100644
--- a/src/com/android/settings/MediaFormat.java
+++ b/src/com/android/settings/MediaFormat.java
@@ -16,23 +16,15 @@
package com.android.settings;
-import com.android.internal.widget.LockPatternUtils;
-
import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.os.IMountService;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.os.Environment;
-import android.text.TextUtils;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import com.android.internal.os.storage.ExternalStorageFormatter;
+
/**
* Confirm and execute a format of the sdcard.
* Multiple confirmations are required: first, a general "are you sure
@@ -46,7 +38,6 @@ public class MediaFormat extends Activity {
private static final int KEYGUARD_REQUEST = 55;
private LayoutInflater mInflater;
- private LockPatternUtils mLockUtils;
private View mInitialView;
private Button mInitiateButton;
@@ -54,31 +45,23 @@ public class MediaFormat extends Activity {
private View mFinalView;
private Button mFinalButton;
- /**
+ /**
* The user has gone through the multiple confirmation, so now we go ahead
* and invoke the Mount Service to format the SD card.
*/
private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
public void onClick(View v) {
-
- // Those monkeys kept committing suicide, so we add this property
- // to disable going through with the format
- if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) {
+
+ if (Utils.isMonkeyRunning()) {
return;
}
- IMountService service =
- IMountService.Stub.asInterface(ServiceManager.getService("mount"));
- if (service != null) {
- try {
- service.formatMedia(Environment.getExternalStorageDirectory().toString());
- } catch (android.os.RemoteException e) {
- // Intentionally blank - there's nothing we can do here
- Log.w("MediaFormat", "Unable to invoke IMountService.formatMedia()");
- }
- } else {
- Log.w("MediaFormat", "Unable to locate IMountService");
- }
- finish();
+ Intent i = getIntent();
+ String path = i.getStringExtra("path");
+ Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY);
+ intent.putExtra("path", path);
+ intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+ startService(intent);
+ finish();
}
};
@@ -86,16 +69,11 @@ public void onClick(View v) {
* Keyguard validation is run using the standard {@link ConfirmLockPattern}
* component as a subactivity
*/
- private void runKeyguardConfirmation() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ConfirmLockPattern");
- // supply header and footer text in the intent
- intent.putExtra(ConfirmLockPattern.HEADER_TEXT,
- getText(R.string.media_format_gesture_prompt));
- intent.putExtra(ConfirmLockPattern.FOOTER_TEXT,
- getText(R.string.media_format_gesture_explanation));
- startActivityForResult(intent, KEYGUARD_REQUEST);
+ private boolean runKeyguardConfirmation(int request) {
+ return new ChooseLockSettingsHelper(this)
+ .launchConfirmationActivity(request,
+ getText(R.string.media_format_gesture_prompt),
+ getText(R.string.media_format_gesture_explanation));
}
@Override
@@ -110,6 +88,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK) {
establishFinalConfirmationState();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ finish();
} else {
establishInitialState();
}
@@ -122,9 +102,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
*/
private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
public void onClick(View v) {
- if (mLockUtils.isLockPatternEnabled()) {
- runKeyguardConfirmation();
- } else {
+ if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
establishFinalConfirmationState();
}
}
@@ -149,7 +127,7 @@ private void establishFinalConfirmationState() {
* click in order to initiate a confirmation sequence. This method is
* called from various other points in the code to reset the activity to
* this base state.
- *
+ *
* Reinflating views from resources is expensive and prevents us from
* caching widget pointers, so we use a single-inflate pattern: we lazy-
* inflate each view, caching all of the widget pointers we'll need at the
@@ -174,7 +152,6 @@ protected void onCreate(Bundle savedState) {
mInitialView = null;
mFinalView = null;
mInflater = LayoutInflater.from(this);
- mLockUtils = new LockPatternUtils(getContentResolver());
establishInitialState();
}
@@ -187,7 +164,8 @@ protected void onCreate(Bundle savedState) {
public void onPause() {
super.onPause();
- establishInitialState();
+ if (!isFinishing()) {
+ establishInitialState();
+ }
}
-
}
diff --git a/src/com/android/settings/PickWidgetDialog.java b/src/com/android/settings/PickWidgetDialog.java
new file mode 100644
index 00000000000..b2d1a40483d
--- /dev/null
+++ b/src/com/android/settings/PickWidgetDialog.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Florian Sundermann
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+
+public class PickWidgetDialog {
+
+ AlertDialog fDialog;
+ private final AppWidgetPickActivity fOwner;
+
+ private class ClickListener implements DialogInterface.OnClickListener {
+
+ public ClickListener() {
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ SubItem subItem = PickWidgetDialog.this.fItemAdapter.getItem(which);
+ PickWidgetDialog.this.fDialog.dismiss();
+
+ PickWidgetDialog.this.showDialog(subItem);
+ }
+
+ }
+
+ private class CancelListener implements OnCancelListener {
+ private final boolean fCancelOwner;
+
+ public CancelListener(boolean cancelOwner) {
+ fCancelOwner = cancelOwner;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ if (fCancelOwner) {
+ PickWidgetDialog.this.fOwner.setResult(AppWidgetPickActivity.RESULT_CANCELED);
+ PickWidgetDialog.this.fOwner.finish();
+ } else {
+ PickWidgetDialog.this.showDialog(null);
+ }
+ }
+ }
+
+
+
+ public PickWidgetDialog(AppWidgetPickActivity owner) {
+ fOwner = owner;
+ }
+
+ ItemAdapter fItemAdapter;
+
+ public void showDialog(SubItem subItem) {
+ if (subItem == null || subItem instanceof Item) {
+ AlertDialog.Builder ab = new AlertDialog.Builder(fOwner);
+
+ if (subItem == null) {
+ ab.setTitle(fOwner.getString(R.string.widget_picker_title));
+ fItemAdapter = new ItemAdapter(fOwner, 0, fOwner.getItems());
+ ab.setAdapter(fItemAdapter, new ClickListener());
+ }
+ else {
+ Item itm = (Item)subItem;
+ if (itm.getItems().size() == 1) {
+ fOwner.finishOk(itm.getItems().get(0));
+ return;
+ }
+
+ ab.setTitle(subItem.getName());
+ fItemAdapter = new ItemAdapter(fOwner, 0, itm.getItems());
+ ab.setAdapter(fItemAdapter, new ClickListener());
+ }
+
+ ab.setOnCancelListener(new CancelListener(subItem == null));
+ fDialog = ab.create();
+ fDialog.show();
+ }
+ else
+ fOwner.finishOk(subItem);
+ }
+}
diff --git a/src/com/android/settings/PrivacySettings.java b/src/com/android/settings/PrivacySettings.java
new file mode 100644
index 00000000000..29deacf2929
--- /dev/null
+++ b/src/com/android/settings/PrivacySettings.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.backup.IBackupManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.preference.CheckBoxPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.text.method.LinkMovementMethod;
+import android.widget.TextView;
+
+/**
+ * Gesture lock pattern settings.
+ */
+public class PrivacySettings extends PreferenceActivity implements
+ DialogInterface.OnClickListener {
+
+ // Vendor specific
+ private static final String GSETTINGS_PROVIDER = "com.google.settings";
+ private static final String BACKUP_CATEGORY = "backup_category";
+ private static final String BACKUP_DATA = "backup_data";
+ private static final String AUTO_RESTORE = "auto_restore";
+ private CheckBoxPreference mBackup;
+ private CheckBoxPreference mAutoRestore;
+ private Dialog mConfirmDialog;
+
+ private static final int DIALOG_ERASE_BACKUP = 2;
+ private int mDialogType;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.privacy_settings);
+ final PreferenceScreen screen = getPreferenceScreen();
+
+ mBackup = (CheckBoxPreference) screen.findPreference(BACKUP_DATA);
+ mAutoRestore = (CheckBoxPreference) screen.findPreference(AUTO_RESTORE);
+
+ // Vendor specific
+ if (getPackageManager().resolveContentProvider(GSETTINGS_PROVIDER, 0) == null) {
+ screen.removePreference(findPreference(BACKUP_CATEGORY));
+ }
+ updateToggles();
+ }
+
+ @Override
+ public void onStop() {
+ if (mConfirmDialog != null && mConfirmDialog.isShowing()) {
+ mConfirmDialog.dismiss();
+ }
+ mConfirmDialog = null;
+ mDialogType = 0;
+ super.onStop();
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+ Preference preference) {
+ if (preference == mBackup) {
+ if (!mBackup.isChecked()) {
+ showEraseBackupDialog();
+ } else {
+ setBackupEnabled(true);
+ }
+ } else if (preference == mAutoRestore) {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ // TODO: disable via the backup manager interface
+ boolean curState = mAutoRestore.isChecked();
+ try {
+ bm.setAutoRestore(curState);
+ } catch (RemoteException e) {
+ mAutoRestore.setChecked(!curState);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void showEraseBackupDialog() {
+ mBackup.setChecked(true);
+
+ mDialogType = DIALOG_ERASE_BACKUP;
+ CharSequence msg = getResources().getText(R.string.backup_erase_dialog_message);
+ mConfirmDialog = new AlertDialog.Builder(this).setMessage(msg)
+ .setTitle(R.string.backup_erase_dialog_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .show();
+ }
+
+ /*
+ * Creates toggles for each available location provider
+ */
+ private void updateToggles() {
+ ContentResolver res = getContentResolver();
+
+ final boolean backupEnabled = Settings.Secure.getInt(res,
+ Settings.Secure.BACKUP_ENABLED, 0) == 1;
+ mBackup.setChecked(backupEnabled);
+
+ mAutoRestore.setChecked(Settings.Secure.getInt(res,
+ Settings.Secure.BACKUP_AUTO_RESTORE, 1) == 1);
+ mAutoRestore.setEnabled(backupEnabled);
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ //updateProviders();
+ if (mDialogType == DIALOG_ERASE_BACKUP) {
+ setBackupEnabled(false);
+ }
+ } else {
+ if (mDialogType == DIALOG_ERASE_BACKUP) {
+ mBackup.setChecked(true);
+ mAutoRestore.setEnabled(true);
+ }
+ }
+ mDialogType = 0;
+ }
+
+ /**
+ * Informs the BackupManager of a change in backup state - if backup is disabled,
+ * the data on the server will be erased.
+ * @param enable whether to enable backup
+ */
+ private void setBackupEnabled(boolean enable) {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ try {
+ bm.setBackupEnabled(enable);
+ } catch (RemoteException e) {
+ mBackup.setChecked(!enable);
+ mAutoRestore.setEnabled(!enable);
+ return;
+ }
+ }
+ mBackup.setChecked(enable);
+ mAutoRestore.setEnabled(enable);
+ }
+}
diff --git a/src/com/android/settings/ProfileConfig.java b/src/com/android/settings/ProfileConfig.java
new file mode 100644
index 00000000000..3cfdf385ee5
--- /dev/null
+++ b/src/com/android/settings/ProfileConfig.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.app.ConnectionSettings;
+import android.app.Dialog;
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.app.ProfileManager;
+import android.app.StreamSettings;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.widget.Toast;
+
+import java.util.UUID;
+
+public class ProfileConfig extends PreferenceActivity implements OnPreferenceChangeListener {
+
+ static final String TAG = "ProfileConfig";
+
+ private static final int DELETE_CONFIRM = 0;
+
+ private ProfileManager mProfileManager;
+
+ private Profile mProfile;
+
+ private EditTextPreference mNamePreference;
+
+ private PreferenceScreen mDeletePreference;
+
+ //Below line intended for use with upcoming Status Bar Indicator functionality
+ //private CheckBoxPreference mStatusBarPreference;
+
+ private StreamItem[] mStreams;
+
+ private ConnectionItem[] mConnections;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mStreams = new StreamItem[] {
+ new StreamItem(AudioManager.STREAM_ALARM, getString(R.string.alarm_volume_title)),
+ new StreamItem(AudioManager.STREAM_MUSIC, getString(R.string.media_volume_title)),
+ new StreamItem(AudioManager.STREAM_RING,
+ getString(R.string.incoming_call_volume_title)),
+ new StreamItem(AudioManager.STREAM_NOTIFICATION,
+ getString(R.string.notification_volume_title))
+ };
+
+ mConnections = new ConnectionItem[] {
+ new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_BLUETOOTH, getString(R.string.toggleBluetooth)),
+ new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_GPS, getString(R.string.toggleGPS)),
+ new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_WIFI, getString(R.string.toggleWifi)),
+ new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_WIFIAP, getString(R.string.toggleWifiAp))
+ //new ConnectionItem(ConnectivityManager.TYPE_WIMAX, getString(R.string.toggleWimax))
+ };
+
+ addPreferencesFromResource(R.xml.profile_config);
+ getListView().setItemsCanFocus(true);
+
+ mProfileManager = (ProfileManager) this.getSystemService(PROFILE_SERVICE);
+
+ Intent input = getIntent();
+ Bundle extras = input.getExtras();
+ if (extras != null) {
+ mProfile = extras.getParcelable("Profile");
+ }
+
+ if (mProfile == null) {
+ mProfile = new Profile(getString(R.string.new_profile_name));
+ mProfileManager.addProfile(mProfile);
+ }
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ mProfile = mProfileManager.getProfile(mProfile.getUuid());
+
+ fillList();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // Save profile here
+ if (mProfile != null) {
+ mProfileManager.updateProfile(mProfile);
+ }
+ }
+
+ private void fillList() {
+
+ mDeletePreference = (PreferenceScreen) findPreference("profile_delete");
+
+ mNamePreference = (EditTextPreference) findPreference("profile_name");
+
+ mNamePreference.setText(mProfile.getName());
+ mNamePreference.setSummary(mProfile.getName());
+ mNamePreference.setOnPreferenceChangeListener(this);
+
+ //Below lines intended for use with upcoming Status Bar Indicator functionality
+ //mStatusBarPreference = (CheckBoxPreference) findPreference("profile_statusbar");
+ //mStatusBarPreference.setChecked(mProfile.getStatusBarIndicator());
+ //mStatusBarPreference.setOnPreferenceChangeListener(this);
+
+ PreferenceGroup connectionList = (PreferenceGroup) findPreference("profile_connectionoverrides");
+ connectionList.removeAll();
+
+ PreferenceGroup streamList = (PreferenceGroup) findPreference("profile_volumeoverrides");
+ streamList.removeAll();
+
+ for (StreamItem stream : mStreams) {
+ StreamSettings settings = mProfile.getSettingsForStream(stream.mStreamId);
+ if (settings == null) {
+ settings = new StreamSettings(stream.mStreamId);
+ mProfile.setStreamSettings(settings);
+ }
+ stream.mSettings = settings;
+ StreamVolumePreference pref = new StreamVolumePreference(this);
+ pref.setKey("stream_" + stream.mStreamId);
+ pref.setTitle(stream.mLabel);
+ pref.setSummary(getString(R.string.profile_volumeoverrides_summary));
+ pref.setPersistent(false);
+ pref.setStreamItem(stream);
+
+ stream.mCheckbox = pref;
+ streamList.addPreference(pref);
+ }
+
+ for (ConnectionItem connection : mConnections) {
+ ConnectionSettings settings = mProfile.getSettingsForConnection(connection.mConnectionId);
+ if (settings == null) {
+ settings = new ConnectionSettings(connection.mConnectionId);
+ mProfile.setConnectionSettings(settings);
+ }
+ connection.mSettings = settings;
+ ProfileConnectionPreference pref = new ProfileConnectionPreference(this);
+ pref.setKey("connection_" + connection.mConnectionId);
+ pref.setTitle(connection.mLabel);
+ pref.setSummary(getString(R.string.profile_connectionoverrides_summary));
+ pref.setPersistent(false);
+ pref.setConnectionItem(connection);
+
+ connection.mCheckbox = pref;
+ connectionList.addPreference(pref);
+ }
+
+ PreferenceGroup groupList = (PreferenceGroup) findPreference("profile_appgroups");
+ groupList.removeAll();
+
+ for (ProfileGroup profileGroup : mProfile.getProfileGroups()) {
+ PreferenceScreen pref = new PreferenceScreen(this, null);
+ UUID uuid = profileGroup.getUuid();
+
+ pref.setKey(uuid.toString());
+ pref.setTitle(mProfileManager.getNotificationGroup(uuid).getName());
+ // pref.setSummary(R.string.profile_summary);
+ pref.setPersistent(false);
+ // pref.setSelectable(true);
+
+ groupList.addPreference(pref);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference instanceof StreamVolumePreference) {
+ for (StreamItem stream : mStreams) {
+ if (preference == stream.mCheckbox) {
+ stream.mSettings.setOverride((Boolean) newValue);
+ }
+ }
+ } else if (preference instanceof ProfileConnectionPreference) {
+ for (ConnectionItem connection : mConnections) {
+ if (preference == connection.mCheckbox) {
+ connection.mSettings.setOverride((Boolean) newValue);
+ }
+ }
+ }
+ // Check name isn't already in use.
+ if (preference == mNamePreference) {
+ String value = (String) newValue;
+ if (mProfileManager.profileExists(value)) {
+ // Rollback the change.
+ return false;
+ }
+ mProfile.setName(value);
+ preference.setSummary(value);
+ }
+ //Below lines intended for use with upcoming Status Bar Indicator functionality
+ /*
+ if (preference == mStatusBarPreference) {
+ mProfile.setStatusBarIndicator((Boolean) newValue);
+ mProfileManager.updateProfile(mProfile);
+ }
+ */
+ return true;
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference instanceof PreferenceScreen) {
+ if (preference == mDeletePreference) {
+ deleteProfile();
+ } else {
+ Intent intent = new Intent(this, ProfileGroupConfig.class);
+ intent.putExtra("ProfileGroup", preference.getKey());
+ intent.putExtra("Profile", mProfile);
+ startActivity(intent);
+ }
+ return true;
+ }
+
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void deleteProfile() {
+ if (mProfile.getUuid().equals(mProfileManager.getActiveProfile().getUuid())) {
+ Toast toast = Toast.makeText(this, getString(R.string.profile_cannot_delete),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ } else {
+ showDialog(DELETE_CONFIRM);
+ }
+ }
+
+ private void doDelete() {
+ mProfileManager.removeProfile(mProfile);
+ mProfile = null;
+ finish();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ final Dialog dialog;
+ switch (id) {
+ case DELETE_CONFIRM:
+ builder.setMessage(R.string.profile_delete_confirm);
+ builder.setPositiveButton(android.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ doDelete();
+ }
+ });
+ builder.setNegativeButton(android.R.string.no,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ dialog = builder.create();
+ break;
+ default:
+ dialog = null;
+ }
+ return dialog;
+ }
+
+ static class StreamItem {
+ int mStreamId;
+
+ String mLabel;
+
+ StreamSettings mSettings;
+
+ StreamVolumePreference mCheckbox;
+
+ public StreamItem(int streamId, String label) {
+ mStreamId = streamId;
+ mLabel = label;
+ }
+ }
+
+ static class ConnectionItem {
+ int mConnectionId;
+
+ String mLabel;
+
+ ConnectionSettings mSettings;
+
+ ProfileConnectionPreference mCheckbox;
+
+ public ConnectionItem(int connectionId, String label) {
+ mConnectionId = connectionId;
+ mLabel = label;
+ }
+ }
+
+}
diff --git a/src/com/android/settings/ProfileConnectionPreference.java b/src/com/android/settings/ProfileConnectionPreference.java
new file mode 100644
index 00000000000..0e44b3df709
--- /dev/null
+++ b/src/com/android/settings/ProfileConnectionPreference.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.RelativeLayout;
+
+public class ProfileConnectionPreference extends Preference implements
+ CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+
+ private boolean mProtectFromCheckedChange = false;
+
+ private CheckBox mCheckBox;
+
+ final static String TAG = "ProfileConnectionPreference";
+
+ private ProfileConfig.ConnectionItem mConnectionItem;
+
+ final static int defaultChoice = -1;
+ private int currentChoice;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public ProfileConnectionPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public ProfileConnectionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public ProfileConnectionPreference(Context context) {
+ super(context);
+ init();
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ View view = super.getView(convertView, parent);
+
+ View widget = view.findViewById(R.id.profile_checkbox);
+ if ((widget != null) && widget instanceof CheckBox) {
+ mCheckBox = (CheckBox) widget;
+ mCheckBox.setOnCheckedChangeListener(this);
+
+ mProtectFromCheckedChange = true;
+ mCheckBox.setChecked(isChecked());
+ mProtectFromCheckedChange = false;
+ }
+
+ View textLayout = view.findViewById(R.id.text_layout);
+ if ((textLayout != null) && textLayout instanceof RelativeLayout) {
+ textLayout.setOnClickListener(this);
+ }
+
+ return view;
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.streamvolume_preference_layout);
+ }
+
+ public boolean isChecked() {
+ return mConnectionItem != null && mConnectionItem.mSettings.isOverride();
+ }
+
+ public void setConnectionItem(ProfileConfig.ConnectionItem connectionItem) {
+ mConnectionItem = connectionItem;
+
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(mConnectionItem.mSettings.isOverride());
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Log.d(TAG, "ID: " + getKey() + " :" + isChecked);
+ if (mProtectFromCheckedChange) {
+ return;
+ }
+
+ mConnectionItem.mSettings.setOverride(isChecked);
+
+ callChangeListener(isChecked);
+ }
+
+ protected Dialog createConnectionDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ final String[] ConnectionValues = getContext().getResources().getStringArray(R.array.profile_connection_values);
+ final Dialog dialog;
+
+ currentChoice = mConnectionItem.mSettings.getValue();
+
+ builder.setTitle(mConnectionItem.mLabel);
+ builder.setSingleChoiceItems(R.array.profile_connection_entries, currentChoice, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ currentChoice = item;
+ }
+ });
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if (currentChoice != defaultChoice) {
+ mConnectionItem.mSettings.setValue(Integer.parseInt(ConnectionValues[currentChoice]));
+ }
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ }
+ });
+ return builder.create();
+ }
+
+ public ProfileConfig.ConnectionItem getConnectionItem() {
+ return mConnectionItem;
+ }
+
+ @Override
+ public void onClick(android.view.View v) {
+ if ((v != null) && (R.id.text_layout == v.getId())) {
+ createConnectionDialog().show();
+ }
+ }
+
+}
diff --git a/src/com/android/settings/ProfileGroupConfig.java b/src/com/android/settings/ProfileGroupConfig.java
new file mode 100644
index 00000000000..18b4f4376e5
--- /dev/null
+++ b/src/com/android/settings/ProfileGroupConfig.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.app.ProfileGroup.Mode;
+import android.app.ProfileManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceActivity;
+
+import java.util.UUID;
+
+public class ProfileGroupConfig extends PreferenceActivity implements OnPreferenceChangeListener {
+
+ private static final CharSequence KEY_SOUNDMODE = "sound_mode";
+
+ private static final CharSequence KEY_VIBRATEMODE = "vibrate_mode";
+
+ private static final CharSequence KEY_LIGHTSMODE = "lights_mode";
+
+ private static final CharSequence KEY_RINGERMODE = "ringer_mode";
+
+ private static final CharSequence KEY_SOUNDTONE = "soundtone";
+
+ private static final CharSequence KEY_RINGTONE = "ringtone";
+
+ Profile mProfile;
+
+ ProfileGroup mProfileGroup;
+
+ private ListPreference mSoundMode;
+
+ private ListPreference mRingerMode;
+
+ private ListPreference mVibrateMode;
+
+ private ListPreference mLightsMode;
+
+ private ProfileRingtonePreference mRingTone;
+
+ private ProfileRingtonePreference mSoundTone;
+
+ private ProfileManager mProfileManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.profile_settings);
+
+ mProfileManager = (ProfileManager) getSystemService(PROFILE_SERVICE);
+ mProfile = (Profile) getIntent().getParcelableExtra("Profile");
+
+ UUID uuid = UUID.fromString(getIntent().getStringExtra("ProfileGroup"));
+ String name = mProfileManager.getNotificationGroup(uuid).getName();
+
+ mProfileGroup = mProfile.getProfileGroup(uuid);
+
+ setTitle(getString(R.string.profile_group_header, mProfile.getName(), name));
+
+ mRingerMode = (ListPreference) findPreference(KEY_RINGERMODE);
+ mSoundMode = (ListPreference) findPreference(KEY_SOUNDMODE);
+ mVibrateMode = (ListPreference) findPreference(KEY_VIBRATEMODE);
+ mLightsMode = (ListPreference) findPreference(KEY_LIGHTSMODE);
+ mRingTone = (ProfileRingtonePreference) findPreference(KEY_RINGTONE);
+ mSoundTone = (ProfileRingtonePreference) findPreference(KEY_SOUNDTONE);
+
+ mRingTone.setShowSilent(false);
+ mSoundTone.setShowSilent(false);
+
+ mSoundMode.setOnPreferenceChangeListener(this);
+ mRingerMode.setOnPreferenceChangeListener(this);
+ mVibrateMode.setOnPreferenceChangeListener(this);
+ mLightsMode.setOnPreferenceChangeListener(this);
+ mSoundTone.setOnPreferenceChangeListener(this);
+ mRingTone.setOnPreferenceChangeListener(this);
+
+ updateState();
+ }
+
+ private void updateState() {
+
+ mVibrateMode.setValue(mProfileGroup.getVibrateMode().name());
+ mSoundMode.setValue(mProfileGroup.getSoundMode().name());
+ mRingerMode.setValue(mProfileGroup.getRingerMode().name());
+ mLightsMode.setValue(mProfileGroup.getLightsMode().name());
+
+ mVibrateMode.setSummary(mVibrateMode.getEntry());
+ mSoundMode.setSummary(mSoundMode.getEntry());
+ mRingerMode.setSummary(mRingerMode.getEntry());
+ mLightsMode.setSummary(mLightsMode.getEntry());
+
+ if (mProfileGroup.getSoundOverride() != null) {
+ mSoundTone.setRingtone(mProfileGroup.getSoundOverride());
+ }
+
+ if (mProfileGroup.getRingerOverride() != null) {
+ mRingTone.setRingtone(mProfileGroup.getRingerOverride());
+ }
+
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mVibrateMode) {
+ mProfileGroup.setVibrateMode(Mode.valueOf((String) newValue));
+ }
+ if (preference == mSoundMode) {
+ mProfileGroup.setSoundMode(Mode.valueOf((String) newValue));
+ }
+ if (preference == mRingerMode) {
+ mProfileGroup.setRingerMode(Mode.valueOf((String) newValue));
+ }
+ if (preference == mLightsMode) {
+ mProfileGroup.setLightsMode(Mode.valueOf((String) newValue));
+ }
+ if (preference == mRingTone) {
+ Uri uri = Uri.parse((String) newValue);
+ mProfileGroup.setRingerOverride(uri);
+ }
+ if (preference == mSoundTone) {
+ Uri uri = Uri.parse((String) newValue);
+ mProfileGroup.setSoundOverride(uri);
+ }
+
+ mProfileManager.updateProfile(mProfile);
+
+ updateState();
+ return true;
+ }
+
+}
diff --git a/src/com/android/settings/ProfileList.java b/src/com/android/settings/ProfileList.java
new file mode 100644
index 00000000000..46d2972babd
--- /dev/null
+++ b/src/com/android/settings/ProfileList.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import java.util.UUID;
+
+import android.app.AlertDialog;
+import android.app.Profile;
+import android.app.ProfileManager;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+
+public class ProfileList extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener {
+ static final String TAG = "ProfileSettings";
+
+ public static final String EXTRA_POSITION = "position";
+
+ public static final String RESTORE_CARRIERS_URI = "content://telephony/carriers/restore";
+
+ public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
+
+ private Preference mResetAllPref;
+
+ private String mSelectedKey;
+
+ private ProfileManager mProfileManager;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ addPreferencesFromResource(R.xml.profile_list);
+ getListView().setItemsCanFocus(true);
+
+ mResetAllPref = findPreference("profile_reset_all");
+
+ mProfileManager = (ProfileManager) this.getSystemService(PROFILE_SERVICE);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ fillList();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ private void fillList() {
+
+ PreferenceGroup profileList = (PreferenceGroup) findPreference("profile_title");
+ profileList.removeAll();
+
+ mSelectedKey = mProfileManager.getActiveProfile().getUuid().toString();
+
+ for(Profile profile : mProfileManager.getProfiles()){
+
+ ProfilePreference pref = new ProfilePreference(this);
+
+ pref.setKey(profile.getUuid().toString());
+ pref.setTitle(profile.getName());
+ pref.setSummary(R.string.profile_summary);
+ pref.setPersistent(false);
+ pref.setOnPreferenceChangeListener(this);
+ pref.setProfile(profile);
+
+ pref.setSelectable(true);
+ if ((mSelectedKey != null) && mSelectedKey.equals(pref.getKey())) {
+ pref.setChecked();
+ }
+ profileList.addPreference(pref);
+ }
+
+ }
+
+ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
+ if (preference == mResetAllPref) {
+ AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ alert.setTitle(R.string.profile_reset_all_title);
+ alert.setMessage(R.string.profile_reset_all_message);
+ alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ mProfileManager.resetAll();
+ fillList();
+ }
+ });
+ alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ alert.create().show();
+ }
+ return false;
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Log.d(TAG, "onPreferenceChange(): Preference - " + preference + ", newValue - " + newValue
+ + ", newValue type - " + newValue.getClass());
+ if (newValue instanceof String) {
+ setSelectedProfile((String) newValue);
+ }
+
+ return true;
+ }
+
+ private void setSelectedProfile(String key) {
+ try {
+ UUID selectedUuid = UUID.fromString(key);
+ mProfileManager.setActiveProfile(selectedUuid);
+ mSelectedKey = key;
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/com/android/settings/ProfilePreference.java b/src/com/android/settings/ProfilePreference.java
new file mode 100644
index 00000000000..c5f6b792734
--- /dev/null
+++ b/src/com/android/settings/ProfilePreference.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.Profile;
+import android.content.Context;
+import android.content.Intent;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.RadioButton;
+import android.widget.RelativeLayout;
+
+public class ProfilePreference extends Preference implements
+ CompoundButton.OnCheckedChangeListener, OnClickListener {
+ final static String TAG = "ProfilePreference";
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public ProfilePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public ProfilePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public ProfilePreference(Context context) {
+ super(context);
+ init();
+ }
+
+ private static String mSelectedKey = null;
+
+ private static CompoundButton mCurrentChecked = null;
+
+ private boolean mProtectFromCheckedChange = false;
+
+ private boolean mSelectable = true;
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ View view = super.getView(convertView, parent);
+
+ View widget = view.findViewById(R.id.profile_radiobutton);
+ if ((widget != null) && widget instanceof RadioButton) {
+ RadioButton rb = (RadioButton) widget;
+ if (mSelectable) {
+ rb.setOnCheckedChangeListener(this);
+
+ boolean isChecked = getKey().equals(mSelectedKey);
+ if (isChecked) {
+ mCurrentChecked = rb;
+ mSelectedKey = getKey();
+ }
+
+ mProtectFromCheckedChange = true;
+ rb.setChecked(isChecked);
+ mProtectFromCheckedChange = false;
+ } else {
+ rb.setVisibility(View.GONE);
+ }
+ }
+
+ View textLayout = view.findViewById(R.id.text_layout);
+ if ((textLayout != null) && textLayout instanceof RelativeLayout) {
+ textLayout.setOnClickListener(this);
+ }
+
+ return view;
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.profile_preference_layout);
+ }
+
+ public boolean isChecked() {
+ return getKey().equals(mSelectedKey);
+ }
+
+ public void setChecked() {
+ mSelectedKey = getKey();
+ }
+
+ private Profile mProfile;
+
+ public void setProfile(Profile profile) {
+ mProfile = profile;
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Log.i(TAG, "ID: " + getKey() + " :" + isChecked);
+ if (mProtectFromCheckedChange) {
+ return;
+ }
+
+ if (isChecked) {
+ if (mCurrentChecked != null) {
+ mCurrentChecked.setChecked(false);
+ }
+ mCurrentChecked = buttonView;
+ mSelectedKey = getKey();
+ callChangeListener(mSelectedKey);
+ } else {
+ mCurrentChecked = null;
+ mSelectedKey = null;
+ }
+ }
+
+ public void onClick(android.view.View v) {
+ if ((v != null) && (R.id.text_layout == v.getId())) {
+ Context context = getContext();
+ if (context != null) {
+ Intent intent = new Intent(context, ProfileConfig.class);
+ intent.putExtra("Profile", mProfile);
+ context.startActivity(intent);
+ }
+ }
+ }
+
+ public void setSelectable(boolean selectable) {
+ mSelectable = selectable;
+ }
+
+ public boolean getSelectable() {
+ return mSelectable;
+ }
+}
diff --git a/src/com/android/settings/ProfileRingtonePreference.java b/src/com/android/settings/ProfileRingtonePreference.java
new file mode 100644
index 00000000000..e81cada0f86
--- /dev/null
+++ b/src/com/android/settings/ProfileRingtonePreference.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.preference.RingtonePreference;
+import android.util.AttributeSet;
+
+public class ProfileRingtonePreference extends RingtonePreference {
+ private static final String TAG = "ProfileRingtonePreference";
+
+ public ProfileRingtonePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) {
+ super.onPrepareRingtonePickerIntent(ringtonePickerIntent);
+
+ /*
+ * Since this preference is for choosing the default ringtone, it
+ * doesn't make sense to show a 'Default' item.
+ */
+ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
+ }
+
+ private Uri mRingtone;
+
+ void setRingtone(Uri uri) {
+ mRingtone = uri;
+ }
+
+ @Override
+ protected Uri onRestoreRingtone() {
+ if (mRingtone == null) {
+ return super.onRestoreRingtone();
+ } else {
+ return mRingtone;
+ }
+ }
+
+}
diff --git a/src/com/android/settings/ProgressCategory.java b/src/com/android/settings/ProgressCategory.java
index 15810b33824..f611137a528 100644
--- a/src/com/android/settings/ProgressCategory.java
+++ b/src/com/android/settings/ProgressCategory.java
@@ -26,7 +26,8 @@
public class ProgressCategory extends PreferenceCategory {
private boolean mProgress = false;
-
+ private View oldView = null;
+
public ProgressCategory(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.preference_progress_category);
@@ -41,6 +42,13 @@ public void onBindView(View view) {
int visibility = mProgress ? View.VISIBLE : View.INVISIBLE;
textView.setVisibility(visibility);
progressBar.setVisibility(visibility);
+
+ if (oldView != null) {
+ oldView.findViewById(R.id.scanning_progress).setVisibility(View.GONE);
+ oldView.findViewById(R.id.scanning_text).setVisibility(View.GONE);
+ oldView.setVisibility(View.GONE);
+ }
+ oldView = view;
}
/**
diff --git a/src/com/android/settings/ProxySelector.java b/src/com/android/settings/ProxySelector.java
index 80fe3c90c98..66c81c62212 100644
--- a/src/com/android/settings/ProxySelector.java
+++ b/src/com/android/settings/ProxySelector.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Proxy;
@@ -73,6 +74,7 @@ public class ProxySelector extends Activity
HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
}
+ private static final int ERROR_DIALOG_ID = 0;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -84,13 +86,32 @@ public void onCreate(Bundle icicle) {
populateFields(false);
}
- protected void showError(int error) {
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ if (id == ERROR_DIALOG_ID) {
+ String hostname = mHostnameField.getText().toString().trim();
+ String portStr = mPortField.getText().toString().trim();
+ String msg = getString(validate(hostname, portStr));
+
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.proxy_error)
+ .setPositiveButton(R.string.proxy_error_dismiss, null)
+ .setMessage(msg)
+ .create();
+ }
+ return super.onCreateDialog(id);
+ }
- new AlertDialog.Builder(this)
- .setTitle(R.string.proxy_error)
- .setMessage(error)
- .setPositiveButton(R.string.proxy_error_dismiss, null)
- .show();
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ super.onPrepareDialog(id, dialog);
+
+ if (id == ERROR_DIALOG_ID) {
+ String hostname = mHostnameField.getText().toString().trim();
+ String portStr = mPortField.getText().toString().trim();
+ String msg = getString(validate(hostname, portStr));
+ ((AlertDialog)dialog).setMessage(msg);
+ }
}
void initView() {
@@ -188,7 +209,7 @@ boolean saveToDb() {
int result = validate(hostname, portStr);
if (result > 0) {
- showError(result);
+ showDialog(ERROR_DIALOG_ID);
return false;
}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 257122bbdf6..56c52619aba 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -20,6 +20,8 @@
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.Uri;
@@ -37,6 +39,7 @@
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.NeighboringCellInfo;
+import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.text.format.DateUtils;
import android.util.Log;
@@ -51,12 +54,12 @@
import android.widget.TextView;
import android.widget.EditText;
+import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.gsm.GSMPhone;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
@@ -70,9 +73,11 @@
import java.util.ArrayList;
import java.util.List;
+import android.util.Log;
+
public class RadioInfo extends Activity {
private final String TAG = "phone";
-
+
private static final int EVENT_PHONE_STATE_CHANGED = 100;
private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200;
private static final int EVENT_SERVICE_STATE_CHANGED = 300;
@@ -81,8 +86,6 @@ public class RadioInfo extends Activity {
private static final int EVENT_QUERY_PREFERRED_TYPE_DONE = 1000;
private static final int EVENT_SET_PREFERRED_TYPE_DONE = 1001;
private static final int EVENT_QUERY_NEIGHBORING_CIDS_DONE = 1002;
- private static final int EVENT_SET_QXDMLOG_DONE = 1003;
- private static final int EVENT_SET_CIPHER_DONE = 1004;
private static final int EVENT_QUERY_SMSC_DONE = 1005;
private static final int EVENT_UPDATE_SMSC_DONE = 1006;
@@ -92,7 +95,9 @@ public class RadioInfo extends Activity {
private static final int MENU_ITEM_VIEW_SDN = 3;
private static final int MENU_ITEM_GET_PDP_LIST = 4;
private static final int MENU_ITEM_TOGGLE_DATA = 5;
- private static final int MENU_ITEM_TOGGLE_DATA_ON_BOOT = 6;
+
+ static final String ENABLE_DATA_STR = "Enable data connection";
+ static final String DISABLE_DATA_STR = "Disable data connection";
private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
private TextView number;
@@ -117,16 +122,14 @@ public class RadioInfo extends Activity {
private TextView mPingIpAddr;
private TextView mPingHostname;
private TextView mHttpClientTest;
- private TextView cipherState;
private TextView dnsCheckState;
private EditText smsc;
private Button radioPowerButton;
- private Button qxdmLogButton;
- private Button cipherToggleButton;
private Button dnsCheckToggleButton;
private Button pingTestButton;
private Button updateSmscButton;
private Button refreshSmscButton;
+ private Button oemInfoButton;
private Spinner preferredNetworkType;
private TelephonyManager mTelephonyManager;
@@ -134,11 +137,6 @@ public class RadioInfo extends Activity {
private PhoneStateIntentReceiver mPhoneStateReceiver;
private INetStatService netstat;
- private OemCommands mOem = null;
- private boolean mQxdmLogEnabled;
- // The requested cipher state
- private boolean mCipherOn;
-
private String mPingIpAddrResult;
private String mPingHostnameResult;
private String mHttpClientTestResult;
@@ -195,13 +193,15 @@ public void handleMessage(Message msg) {
break;
case EVENT_QUERY_PREFERRED_TYPE_DONE:
+ preferredNetworkType.setOnItemSelectedListener(null);
ar= (AsyncResult) msg.obj;
if (ar.exception == null) {
int type = ((int[])ar.result)[0];
preferredNetworkType.setSelection(type, true);
} else {
- preferredNetworkType.setSelection(3, true);
+ preferredNetworkType.setSelection(8, true);
}
+ preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
break;
case EVENT_SET_PREFERRED_TYPE_DONE:
ar= (AsyncResult) msg.obj;
@@ -218,22 +218,6 @@ public void handleMessage(Message msg) {
mNeighboringCids.setText("unknown");
}
break;
- case EVENT_SET_QXDMLOG_DONE:
- ar= (AsyncResult) msg.obj;
- if (ar.exception == null) {
- mQxdmLogEnabled = !mQxdmLogEnabled;
-
- updateQxdmState(mQxdmLogEnabled);
- displayQxdmEnableResult();
- }
- break;
- case EVENT_SET_CIPHER_DONE:
- ar= (AsyncResult) msg.obj;
- if (ar.exception == null) {
- setCiphPref(mCipherOn);
- }
- updateCiphState();
- break;
case EVENT_QUERY_SMSC_DONE:
ar= (AsyncResult) msg.obj;
if (ar.exception != null) {
@@ -256,116 +240,6 @@ public void handleMessage(Message msg) {
}
};
- private class OemCommands {
-
- public final int OEM_QXDM_SDLOG_DEFAULT_FILE_SIZE = 32;
- public final int OEM_QXDM_SDLOG_DEFAULT_MASK = 0;
- public final int OEM_QXDM_SDLOG_DEFAULT_MAX_INDEX = 8;
-
- final int SIZE_OF_INT = 4;
- final int OEM_FEATURE_ENABLE = 1;
- final int OEM_FEATURE_DISABLE = 0;
- final int OEM_SIMPE_FEAUTURE_LEN = 1;
-
- final int OEM_QXDM_SDLOG_FUNCTAG = 0x00010000;
- final int OEM_QXDM_SDLOG_LEN = 4;
- final int OEM_PS_AUTO_ATTACH_FUNCTAG = 0x00020000;
- final int OEM_CIPHERING_FUNCTAG = 0x00020001;
-
- /**
- * The OEM interface to store QXDM to SD.
- *
- * To start/stop logging QXDM logs to SD card, use tag
- * OEM_RIL_HOOK_QXDM_SD_LOG_SETUP 0x00010000
- *
- * "data" is a const oem_ril_hook_qxdm_sdlog_setup_data_st *
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->head.func_tag
- * should be OEM_RIL_HOOK_QXDM_SD_LOG_SETUP
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->head.len
- * should be "sizeof(unsigned int) * 4"
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->mode
- * could be 0 for 'stop logging', or 1 for 'start logging'
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_file_size
- * will assign the size of each log file, and it could be a value between
- * 1 and 512 (in megabytes, default value is recommended to set as 32).
- * This value will be ignored when mode == 0.
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_mask will
- * assign the rule to filter logs, and it is a bitmask (bit0 is for MsgAll,
- * bit1 is for LogAll, and bit2 is for EventAll) recommended to be set as 0
- * by default. This value will be ignored when mode == 0.
- * ((const oem_ril_hook_qxdm_sdlog_setup_data_st *)data)->log_max_fileindex
- * set the how many logfiles will storted before roll over. This value will
- * be ignored when mode == 0.
- *
- * "response" is NULL
- *
- * typedef struct _oem_ril_hook_raw_head_st {
- * unsigned int func_tag;
- * unsigned int len;
- * } oem_ril_hook_raw_head_st;
- *
- * typedef struct _oem_ril_hook_qxdm_sdlog_setup_data_st {
- * oem_ril_hook_raw_head_st head;
- * unsigned int mode;
- * unsigned int log_file_size;
- * unsigned int log_mask;
- * unsigned int log_max_fileindex;
- * } oem_ril_hook_qxdm_sdlog_setup_data_st;
- *
- * @param enable set true to start logging QXDM in SD card
- * @param fileSize is the log file size in MB
- * @param mask is the log mask to filter
- * @param maxIndex is the maximum roll-over file number
- * @return byteArray to use in RIL RAW command
- */
- byte[] getQxdmSdlogData(boolean enable, int fileSize, int mask, int maxIndex) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- try {
- writeIntLittleEndian(dos, OEM_QXDM_SDLOG_FUNCTAG);
- writeIntLittleEndian(dos, OEM_QXDM_SDLOG_LEN * SIZE_OF_INT);
- writeIntLittleEndian(dos, enable ?
- OEM_FEATURE_ENABLE : OEM_FEATURE_DISABLE);
- writeIntLittleEndian(dos, fileSize);
- writeIntLittleEndian(dos, mask);
- writeIntLittleEndian(dos, maxIndex);
- } catch (IOException e) {
- return null;
- }
- return bos.toByteArray();
- }
-
- byte[] getPsAutoAttachData(boolean enable) {
- return getSimpleFeatureData(OEM_PS_AUTO_ATTACH_FUNCTAG, enable);
- }
-
- byte[] getCipheringData(boolean enable) {
- return getSimpleFeatureData(OEM_CIPHERING_FUNCTAG, enable);
- }
-
- private byte[] getSimpleFeatureData(int tag, boolean enable) {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- try {
- writeIntLittleEndian(dos, tag);
- writeIntLittleEndian(dos, OEM_SIMPE_FEAUTURE_LEN * SIZE_OF_INT);
- writeIntLittleEndian(dos, enable ?
- OEM_FEATURE_ENABLE : OEM_FEATURE_DISABLE);
- } catch (IOException e) {
- return null;
- }
- return bos.toByteArray();
- }
-
- private void writeIntLittleEndian(DataOutputStream dos, int val)
- throws IOException {
- dos.writeByte(val);
- dos.writeByte(val >> 8);
- dos.writeByte(val >> 16);
- dos.writeByte(val >> 24);
- }
- }
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -396,7 +270,6 @@ public void onCreate(Bundle icicle) {
sentSinceReceived = (TextView) findViewById(R.id.sentSinceReceived);
sent = (TextView) findViewById(R.id.sent);
received = (TextView) findViewById(R.id.received);
- cipherState = (TextView) findViewById(R.id.ciphState);
smsc = (EditText) findViewById(R.id.smsc);
dnsCheckState = (TextView) findViewById(R.id.dnsCheckState);
@@ -407,18 +280,13 @@ public void onCreate(Bundle icicle) {
preferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
ArrayAdapter adapter = new ArrayAdapter (this,
android.R.layout.simple_spinner_item, mPreferredNetworkLabels);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
preferredNetworkType.setAdapter(adapter);
preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
radioPowerButton = (Button) findViewById(R.id.radio_power);
radioPowerButton.setOnClickListener(mPowerButtonHandler);
- qxdmLogButton = (Button) findViewById(R.id.qxdm_log);
- qxdmLogButton.setOnClickListener(mQxdmButtonHandler);
-
- cipherToggleButton = (Button) findViewById(R.id.ciph_toggle);
- cipherToggleButton.setOnClickListener(mCipherButtonHandler);
pingTestButton = (Button) findViewById(R.id.ping_test);
pingTestButton.setOnClickListener(mPingButtonHandler);
updateSmscButton = (Button) findViewById(R.id.update_smsc);
@@ -427,14 +295,20 @@ public void onCreate(Bundle icicle) {
refreshSmscButton.setOnClickListener(mRefreshSmscButtonHandler);
dnsCheckToggleButton = (Button) findViewById(R.id.dns_check_toggle);
dnsCheckToggleButton.setOnClickListener(mDnsCheckButtonHandler);
-
+
+ oemInfoButton = (Button) findViewById(R.id.oem_info);
+ oemInfoButton.setOnClickListener(mOemInfoButtonHandler);
+ PackageManager pm = getPackageManager();
+ Intent oemInfoIntent = new Intent("com.android.settings.OEM_RADIO_INFO");
+ List oemInfoIntentList = pm.queryIntentActivities(oemInfoIntent, 0);
+ if (oemInfoIntentList.size() == 0) {
+ oemInfoButton.setEnabled(false);
+ }
+
mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
mPhoneStateReceiver.notifyPhoneCallState(EVENT_PHONE_STATE_CHANGED);
-
- updateQxdmState(null);
- mOem = new OemCommands();
phone.getPreferredNetworkType(
mHandler.obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
@@ -460,9 +334,7 @@ protected void onResume() {
updateDataStats();
updateDataStats2();
updatePowerState();
- updateQxdmState(null);
updateProperties();
- updateCiphState();
updateDnsCheckState();
Log.i(TAG, "[RadioInfo] onResume: register phone & data intents");
@@ -500,14 +372,10 @@ public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, MENU_ITEM_GET_PDP_LIST,
0, R.string.radioInfo_menu_getPDP).setOnMenuItemClickListener(mGetPdpList);
menu.add(1, MENU_ITEM_TOGGLE_DATA,
- 0, R.string.radioInfo_menu_disableData).setOnMenuItemClickListener(mToggleData);
- menu.add(1, MENU_ITEM_TOGGLE_DATA_ON_BOOT,
- 0, R.string.radioInfo_menu_disableDataOnBoot).setOnMenuItemClickListener(
- mToggleDataOnBoot);
+ 0, DISABLE_DATA_STR).setOnMenuItemClickListener(mToggleData);
return true;
}
-
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Get the TOGGLE DATA menu item in the right state.
@@ -518,33 +386,23 @@ public boolean onPrepareOptionsMenu(Menu menu) {
switch (state) {
case TelephonyManager.DATA_CONNECTED:
case TelephonyManager.DATA_SUSPENDED:
- item.setTitle(R.string.radioInfo_menu_disableData);
+ item.setTitle(DISABLE_DATA_STR);
break;
case TelephonyManager.DATA_DISCONNECTED:
- item.setTitle(R.string.radioInfo_menu_enableData);
+ item.setTitle(ENABLE_DATA_STR);
break;
default:
visible = false;
break;
}
item.setVisible(visible);
-
- // Get the toggle-data-on-boot menu item in the right state.
- item = menu.findItem(MENU_ITEM_TOGGLE_DATA_ON_BOOT);
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- boolean value = sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- if (value) {
- item.setTitle(R.string.radioInfo_menu_enableDataOnBoot);
- } else {
- item.setTitle(R.string.radioInfo_menu_disableDataOnBoot);
- }
return true;
}
private boolean isRadioOn() {
return phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
}
-
+
private void updatePowerState() {
String buttonText = isRadioOn() ?
getString(R.string.turn_off_radio) :
@@ -552,42 +410,6 @@ private void updatePowerState() {
radioPowerButton.setText(buttonText);
}
- private void updateQxdmState(Boolean newQxdmStatus) {
- SharedPreferences sp =
- PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- mQxdmLogEnabled = sp.getBoolean("qxdmstatus", false);
- // This is called from onCreate, onResume, and the handler when the status
- // is updated.
- if (newQxdmStatus != null) {
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean("qxdmstatus", newQxdmStatus);
- editor.commit();
- mQxdmLogEnabled = newQxdmStatus;
- }
-
- String buttonText = mQxdmLogEnabled ?
- getString(R.string.turn_off_qxdm) :
- getString(R.string.turn_on_qxdm);
- qxdmLogButton.setText(buttonText);
- }
-
- private void setCiphPref(boolean value) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(GSMPhone.CIPHERING_KEY, value);
- editor.commit();
- }
-
- private boolean getCiphPref() {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- boolean ret = sp.getBoolean(GSMPhone.CIPHERING_KEY, true);
- return ret;
- }
-
- private void updateCiphState() {
- cipherState.setText(getCiphPref() ? "Ciphering ON" : "Ciphering OFF");
- }
-
private void updateDnsCheckState() {
dnsCheckState.setText(phone.isDnsCheckDisabled() ?
"0.0.0.0 allowed" :"0.0.0.0 not allowed");
@@ -620,38 +442,59 @@ private void updateDnsCheckState() {
}
private final void updateLocation(CellLocation location) {
- int lac = -1;
- int cid = -1;
+ Resources r = getResources();
if (location instanceof GsmCellLocation) {
GsmCellLocation loc = (GsmCellLocation)location;
- lac = loc.getLac();
- cid = loc.getCid();
+ int lac = loc.getLac();
+ int cid = loc.getCid();
+ mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
+ + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
+ + " "
+ + r.getString(R.string.radioInfo_cid) + " = "
+ + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
+ } else if (location instanceof CdmaCellLocation) {
+ CdmaCellLocation loc = (CdmaCellLocation)location;
+ int bid = loc.getBaseStationId();
+ int sid = loc.getSystemId();
+ int nid = loc.getNetworkId();
+ int lat = loc.getBaseStationLatitude();
+ int lon = loc.getBaseStationLongitude();
+ mLocation.setText("BID = "
+ + ((bid == -1) ? "unknown" : Integer.toHexString(bid))
+ + " "
+ + "SID = "
+ + ((sid == -1) ? "unknown" : Integer.toHexString(sid))
+ + " "
+ + "NID = "
+ + ((nid == -1) ? "unknown" : Integer.toHexString(nid))
+ + "\n"
+ + "LAT = "
+ + ((lat == -1) ? "unknown" : Integer.toHexString(lat))
+ + " "
+ + "LONG = "
+ + ((lon == -1) ? "unknown" : Integer.toHexString(lon)));
+ } else {
+ mLocation.setText("unknown");
}
- Resources r = getResources();
- mLocation.setText(r.getString(R.string.radioInfo_lac) + " = "
- + ((lac == -1) ? "unknown" : Integer.toHexString(lac))
- + " "
- + r.getString(R.string.radioInfo_cid) + " = "
- + ((cid == -1) ? "unknown" : Integer.toHexString(cid)));
}
private final void updateNeighboringCids(ArrayList cids) {
- String neighborings = "";
+ StringBuilder sb = new StringBuilder();
+
if (cids != null) {
if ( cids.isEmpty() ) {
- neighborings = "no neighboring cells";
+ sb.append("no neighboring cells");
} else {
for (NeighboringCellInfo cell : cids) {
- neighborings += "{" + Integer.toHexString(cell.getCid())
- + "@" + cell.getRssi() + "} ";
+ sb.append(cell.toString()).append(" ");
}
}
} else {
- neighborings = "unknown";
+ sb.append("unknown");
}
- mNeighboringCids.setText(neighborings);
+ mNeighboringCids.setText(sb.toString());
}
private final void
@@ -671,7 +514,7 @@ private final void updateNeighboringCids(ArrayList cids) {
int state = serviceState.getState();
Resources r = getResources();
String display = r.getString(R.string.radioInfo_unknown);
-
+
switch (state) {
case ServiceState.STATE_IN_SERVICE:
display = r.getString(R.string.radioInfo_service_in);
@@ -684,9 +527,9 @@ private final void updateNeighboringCids(ArrayList cids) {
display = r.getString(R.string.radioInfo_service_off);
break;
}
-
+
gsmState.setText(display);
-
+
if (serviceState.getRoaming()) {
roamingState.setText(R.string.radioInfo_roaming_in);
} else {
@@ -737,7 +580,7 @@ private final void updateNeighboringCids(ArrayList cids) {
display = r.getString(R.string.radioInfo_data_suspended);
break;
}
-
+
gprsState.setText(display);
}
@@ -755,12 +598,12 @@ private final void updateNetworkType() {
Resources r = getResources();
s = phone.getDeviceId();
- if (s == null) s = r.getString(R.string.radioInfo_unknown);
+ if (s == null) s = r.getString(R.string.radioInfo_unknown);
mDeviceId.setText(s);
-
+
s = phone.getLine1Number();
- if (s == null) s = r.getString(R.string.radioInfo_unknown);
+ if (s == null) s = r.getString(R.string.radioInfo_unknown);
number.setText(s);
}
@@ -791,10 +634,10 @@ private final void updateDataStats2() {
long rxPackets = netstat.getMobileRxPackets();
long txBytes = netstat.getMobileTxBytes();
long rxBytes = netstat.getMobileRxBytes();
-
+
String packets = r.getString(R.string.radioInfo_display_packets);
String bytes = r.getString(R.string.radioInfo_display_bytes);
-
+
sent.setText(txPackets + " " + packets + ", " + txBytes + " " + bytes);
received.setText(rxPackets + " " + packets + ", " + rxBytes + " " + bytes);
} catch (RemoteException e) {
@@ -828,7 +671,7 @@ private final void pingIpAddr() {
*/
private final void pingHostname() {
try {
- Process p = Runtime.getRuntime().exec("ping -c 1 www.google.com");
+ Process p = Runtime.getRuntime().exec("ping -c 1 www.google.com");
int status = p.waitFor();
if (status == 0) {
mPingHostnameResult = "Pass";
@@ -916,20 +759,24 @@ public void run() {
private final void updatePdpList() {
StringBuilder sb = new StringBuilder("========DATA=======\n");
- List pdps = phone.getCurrentPdpList();
+ List dcs = phone.getCurrentDataConnectionList();
- for (PdpConnection pdp : pdps) {
- sb.append(" State: ").append(pdp.getState().toString()).append("\n");
- if (pdp.getState().isActive()) {
+ for (DataConnection dc : dcs) {
+ sb.append(" State: ").append(dc.getStateAsString()).append("\n");
+ if (dc.isActive()) {
long timeElapsed =
- (System.currentTimeMillis() - pdp.getConnectionTime())/1000;
+ (System.currentTimeMillis() - dc.getConnectionTime())/1000;
sb.append(" connected at ")
- .append(DateUtils.timeString(pdp.getConnectionTime()))
+ .append(DateUtils.timeString(dc.getConnectionTime()))
.append(" and elapsed ")
- .append(DateUtils.formatElapsedTime(timeElapsed))
- .append("\n to ")
- .append(pdp.getApn().toString())
- .append("\ninterface: ")
+ .append(DateUtils.formatElapsedTime(timeElapsed));
+
+ if (dc instanceof GsmDataConnection) {
+ GsmDataConnection pdp = (GsmDataConnection)dc;
+ sb.append("\n to ")
+ .append(pdp.getApn().toString());
+ }
+ sb.append("\ninterface: ")
.append(phone.getInterfaceName(phone.getActiveApnTypes()[0]))
.append("\naddress: ")
.append(phone.getIpAddress(phone.getActiveApnTypes()[0]))
@@ -939,14 +786,19 @@ private final void updatePdpList() {
if (dns != null) {
sb.append("\ndns: ").append(dns[0]).append(", ").append(dns[1]);
}
- } else if (pdp.getState().isInactive()) {
+ } else if (dc.isInactive()) {
sb.append(" disconnected with last try at ")
- .append(DateUtils.timeString(pdp.getLastFailTime()))
+ .append(DateUtils.timeString(dc.getLastFailTime()))
.append("\n fail because ")
- .append(pdp.getLastFailCause().toString());
+ .append(dc.getLastFailCause().toString());
} else {
- sb.append(" is connecting to ")
- .append(pdp.getApn().toString());
+ if (dc instanceof GsmDataConnection) {
+ GsmDataConnection pdp = (GsmDataConnection)dc;
+ sb.append(" is connecting to ")
+ .append(pdp.getApn().toString());
+ } else {
+ sb.append(" is connecting");
+ }
}
sb.append("\n===================");
}
@@ -955,20 +807,6 @@ private final void updatePdpList() {
disconnects.setText(sb.toString());
}
- private void displayQxdmEnableResult() {
- String status = mQxdmLogEnabled ? "Start QXDM Log" : "Stop QXDM Log";
-
- DialogInterface mProgressPanel = new AlertDialog.
- Builder(this).setMessage(status).show();
-
- mHandler.postDelayed(
- new Runnable() {
- public void run() {
- finish();
- }
- }, 2000);
- }
-
private MenuItem.OnMenuItemClickListener mViewADNCallback = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -1015,28 +853,22 @@ public boolean onMenuItemClick(MenuItem item) {
}
};
- private void toggleDataDisabledOnBoot() {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- SharedPreferences.Editor editor = sp.edit();
- boolean value = sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- editor.putBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, !value);
- byte[] data = mOem.getPsAutoAttachData(value);
- if (data == null) {
- // don't commit
- return;
+ private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ phone.getDataCallList(null);
+ return true;
}
+ };
- editor.commit();
- phone.invokeOemRilRequestRaw(data, null);
- }
-
- private MenuItem.OnMenuItemClickListener mToggleDataOnBoot = new MenuItem.OnMenuItemClickListener() {
+ private MenuItem.OnMenuItemClickListener mSelectBandCallback = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- toggleDataDisabledOnBoot();
+ Intent intent = new Intent();
+ intent.setClass(RadioInfo.this, BandMode.class);
+ startActivity(intent);
return true;
}
};
-
+
private MenuItem.OnMenuItemClickListener mToggleData = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
int state = mTelephonyManager.getDataState();
@@ -1055,22 +887,6 @@ public boolean onMenuItemClick(MenuItem item) {
}
};
- private MenuItem.OnMenuItemClickListener mGetPdpList = new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- phone.getDataCallList(null);
- return true;
- }
- };
-
- private MenuItem.OnMenuItemClickListener mSelectBandCallback = new MenuItem.OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- Intent intent = new Intent();
- intent.setClass(RadioInfo.this, BandMode.class);
- startActivity(intent);
- return true;
- }
- };
-
OnClickListener mPowerButtonHandler = new OnClickListener() {
public void onClick(View v) {
//log("toggle radio power: currently " + (isRadioOn()?"on":"off"));
@@ -1078,27 +894,26 @@ public void onClick(View v) {
}
};
- OnClickListener mCipherButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- mCipherOn = !getCiphPref();
- byte[] data = mOem.getCipheringData(mCipherOn);
-
- if (data == null)
- return;
-
- cipherState.setText("Setting...");
- phone.invokeOemRilRequestRaw(data,
- mHandler.obtainMessage(EVENT_SET_CIPHER_DONE));
- }
- };
-
OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
public void onClick(View v) {
phone.disableDnsCheck(!phone.isDnsCheckDisabled());
updateDnsCheckState();
}
};
-
+
+ OnClickListener mOemInfoButtonHandler = new OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent("com.android.settings.OEM_RADIO_INFO");
+ try {
+ startActivity(intent);
+ } catch (android.content.ActivityNotFoundException ex) {
+ Log.d(TAG, "OEM-specific Info/Settings Activity Not Found : " + ex);
+ // If the activity does not exist, there are no OEM
+ // settings, and so we can just do nothing...
+ }
+ }
+ };
+
OnClickListener mPingButtonHandler = new OnClickListener() {
public void onClick(View v) {
updatePingState();
@@ -1119,22 +934,6 @@ public void onClick(View v) {
}
};
- OnClickListener mQxdmButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- byte[] data = mOem.getQxdmSdlogData(
- !mQxdmLogEnabled,
- mOem.OEM_QXDM_SDLOG_DEFAULT_FILE_SIZE,
- mOem.OEM_QXDM_SDLOG_DEFAULT_MASK,
- mOem.OEM_QXDM_SDLOG_DEFAULT_MAX_INDEX);
-
- if (data == null)
- return;
-
- phone.invokeOemRilRequestRaw(data,
- mHandler.obtainMessage(EVENT_SET_QXDMLOG_DONE));
- }
- };
-
AdapterView.OnItemSelectedListener
mPreferredNetworkHandler = new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView parent, View v, int pos, long id) {
@@ -1149,5 +948,13 @@ public void onNothingSelected(AdapterView parent) {
};
private String[] mPreferredNetworkLabels = {
- "WCDMA preferred", "GSM only", "WCDMA only", "Unknown"};
+ "WCDMA preferred",
+ "GSM only",
+ "WCDMA only",
+ "GSM auto (PRL)",
+ "CDMA auto (PRL)",
+ "CDMA only",
+ "EvDo only",
+ "GSM/CDMA auto (PRL)",
+ "Unknown"};
}
diff --git a/src/com/android/settings/RingerVolumePreference.java b/src/com/android/settings/RingerVolumePreference.java
index 2d21ec6e997..3b1434bbd41 100644
--- a/src/com/android/settings/RingerVolumePreference.java
+++ b/src/com/android/settings/RingerVolumePreference.java
@@ -16,10 +16,12 @@
package com.android.settings;
+import android.app.Dialog;
import android.content.Context;
import android.media.AudioManager;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.preference.VolumePreference;
-import android.preference.VolumePreference.SeekBarVolumizer;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;
@@ -36,36 +38,53 @@ public class RingerVolumePreference extends VolumePreference implements
CheckBox.OnCheckedChangeListener {
private static final String TAG = "RingerVolumePreference";
+ private boolean mOrigNotificationsUseRingVolume;
private CheckBox mNotificationsUseRingVolumeCheckbox;
- private SeekBarVolumizer mNotificationSeekBarVolumizer;
+
+ private SeekBarVolumizer [] mSeekBarVolumizer;
+ private static final int[] SEEKBAR_ID = new int[] {
+ R.id.notification_volume_seekbar,
+ R.id.media_volume_seekbar,
+ R.id.alarm_volume_seekbar
+ };
+ private static final int[] SEEKBAR_TYPE = new int[] {
+ AudioManager.STREAM_NOTIFICATION,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.STREAM_ALARM
+ };
+ //private SeekBarVolumizer mNotificationSeekBarVolumizer;
private TextView mNotificationVolumeTitle;
-
+
public RingerVolumePreference(Context context, AttributeSet attrs) {
super(context, attrs);
// The always visible seekbar is for ring volume
setStreamType(AudioManager.STREAM_RING);
-
+
setDialogLayoutResource(R.layout.preference_dialog_ringervolume);
+ setDialogIcon(R.drawable.ic_settings_sound);
+
+ mSeekBarVolumizer = new SeekBarVolumizer[SEEKBAR_ID.length];
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
-
+
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ SeekBar seekBar = (SeekBar) view.findViewById(SEEKBAR_ID[i]);
+ mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
+ SEEKBAR_TYPE[i]);
+ }
+
+ mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
mNotificationsUseRingVolumeCheckbox =
(CheckBox) view.findViewById(R.id.same_notification_volume);
mNotificationsUseRingVolumeCheckbox.setOnCheckedChangeListener(this);
- mNotificationsUseRingVolumeCheckbox.setChecked(Settings.System.getInt(
+ mOrigNotificationsUseRingVolume = Settings.System.getInt(
getContext().getContentResolver(),
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1);
-
- final SeekBar seekBar = (SeekBar) view.findViewById(R.id.notification_volume_seekbar);
- mNotificationSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar,
- AudioManager.STREAM_NOTIFICATION);
-
- mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
-
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
+ mNotificationsUseRingVolumeCheckbox.setChecked(mOrigNotificationsUseRingVolume);
setNotificationVolumeVisibility(!mNotificationsUseRingVolumeCheckbox.isChecked());
}
@@ -73,10 +92,16 @@ protected void onBindDialogView(View view) {
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
- if (!positiveResult && mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.revertVolume();
- }
-
+ if (!positiveResult) {
+ for (SeekBarVolumizer vol : mSeekBarVolumizer) {
+ if (vol != null) vol.revertVolume();
+ }
+
+ boolean checked = mNotificationsUseRingVolumeCheckbox.isChecked();
+ if (mOrigNotificationsUseRingVolume != checked) {
+ updateNotificationsUseRingVolumeSetting(mOrigNotificationsUseRingVolume);
+ }
+ }
cleanup();
}
@@ -85,45 +110,157 @@ public void onActivityStop() {
super.onActivityStop();
cleanup();
}
-
+
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setNotificationVolumeVisibility(!isChecked);
-
+ updateNotificationsUseRingVolumeSetting(isChecked);
+ }
+
+ @Override
+ protected void onSampleStarting(SeekBarVolumizer volumizer) {
+ super.onSampleStarting(volumizer);
+ for (SeekBarVolumizer vol : mSeekBarVolumizer) {
+ if (vol != null && vol != volumizer) vol.stopSample();
+ }
+ }
+
+ private void updateNotificationsUseRingVolumeSetting(boolean active) {
Settings.System.putInt(getContext().getContentResolver(),
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, isChecked ? 1 : 0);
-
- if (isChecked) {
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME, active ? 1 : 0);
+ if (active) {
// The user wants the notification to be same as ring, so do a
// one-time sync right now
- AudioManager audioManager = (AudioManager) getContext()
- .getSystemService(Context.AUDIO_SERVICE);
+ AudioManager audioManager = (AudioManager)
+ getContext().getSystemService(Context.AUDIO_SERVICE);
audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION,
audioManager.getStreamVolume(AudioManager.STREAM_RING), 0);
}
}
+ private void setNotificationVolumeVisibility(boolean visible) {
+ if (mSeekBarVolumizer[0] != null) {
+ mSeekBarVolumizer[0].getSeekBar().setVisibility(
+ visible ? View.VISIBLE : View.GONE);
+ }
+ mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ private void cleanup() {
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ if (mSeekBarVolumizer[i] != null) {
+ Dialog dialog = getDialog();
+ if (dialog != null && dialog.isShowing()) {
+ // Stopped while dialog was showing, revert changes
+ mSeekBarVolumizer[i].revertVolume();
+ }
+ mSeekBarVolumizer[i].stop();
+ mSeekBarVolumizer[i] = null;
+ }
+ }
+ }
+
@Override
- protected void onSampleStarting(SeekBarVolumizer volumizer) {
- super.onSampleStarting(volumizer);
-
- if (mNotificationSeekBarVolumizer != null && volumizer != mNotificationSeekBarVolumizer) {
- mNotificationSeekBarVolumizer.stopSample();
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
}
+
+ final SavedState myState = new SavedState(superState);
+ VolumeStore[] volumeStore = myState.getVolumeStore(SEEKBAR_ID.length);
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ SeekBarVolumizer vol = mSeekBarVolumizer[i];
+ if (vol != null) {
+ vol.onSaveInstanceState(volumeStore[i]);
+ }
+ }
+
+ if (mNotificationsUseRingVolumeCheckbox != null) {
+ myState.mUseRingVolumeForNotifications =
+ mNotificationsUseRingVolumeCheckbox.isChecked();
+ myState.mOrigUseRingVolumeForNotifications =
+ mOrigNotificationsUseRingVolume;
+ }
+
+ return myState;
}
- private void setNotificationVolumeVisibility(boolean visible) {
- if (mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.getSeekBar().setVisibility(
- visible ? View.VISIBLE : View.GONE);
- mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ VolumeStore[] volumeStore = myState.getVolumeStore(SEEKBAR_ID.length);
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ SeekBarVolumizer vol = mSeekBarVolumizer[i];
+ if (vol != null) {
+ vol.onRestoreInstanceState(volumeStore[i]);
+ }
+ }
+
+ if (mNotificationsUseRingVolumeCheckbox != null) {
+ mNotificationsUseRingVolumeCheckbox.setChecked(myState.mUseRingVolumeForNotifications);
+ mOrigNotificationsUseRingVolume = myState.mOrigUseRingVolumeForNotifications;
}
}
-
- private void cleanup() {
- if (mNotificationSeekBarVolumizer != null) {
- mNotificationSeekBarVolumizer.stop();
- mNotificationSeekBarVolumizer = null;
+
+ private static class SavedState extends BaseSavedState {
+ VolumeStore [] mVolumeStore;
+ boolean mUseRingVolumeForNotifications;
+ boolean mOrigUseRingVolumeForNotifications;
+
+ public SavedState(Parcel source) {
+ super(source);
+ mVolumeStore = new VolumeStore[SEEKBAR_ID.length];
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ mVolumeStore[i] = new VolumeStore();
+ mVolumeStore[i].volume = source.readInt();
+ mVolumeStore[i].originalVolume = source.readInt();
+ }
+ mUseRingVolumeForNotifications = source.readInt() != 0;
+ mOrigUseRingVolumeForNotifications = source.readInt() != 0;
}
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ for (int i = 0; i < SEEKBAR_ID.length; i++) {
+ dest.writeInt(mVolumeStore[i].volume);
+ dest.writeInt(mVolumeStore[i].originalVolume);
+ }
+ dest.writeInt(mUseRingVolumeForNotifications ? 1 : 0);
+ dest.writeInt(mOrigUseRingVolumeForNotifications ? 1 : 0);
+ }
+
+ VolumeStore[] getVolumeStore(int count) {
+ if (mVolumeStore == null || mVolumeStore.length != count) {
+ mVolumeStore = new VolumeStore[count];
+ for (int i = 0; i < count; i++) {
+ mVolumeStore[i] = new VolumeStore();
+ }
+ }
+ return mVolumeStore;
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
}
-
}
diff --git a/src/com/android/settings/SdCardIntentReceiver.java b/src/com/android/settings/SdCardIntentReceiver.java
deleted file mode 100644
index 9648ec1132c..00000000000
--- a/src/com/android/settings/SdCardIntentReceiver.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
-import android.util.Config;
-import android.util.Log;
-
-/**
- *
- */
-public class SdCardIntentReceiver extends BroadcastReceiver {
-
- private static final int SDCARD_STATUS = 1;
- private static final String TAG = "SdCardIntentReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- NotificationManager nm = (NotificationManager) context
- .getSystemService(Context.NOTIFICATION_SERVICE);
- String action = intent.getAction();
- if (Config.LOGD) Log.d(TAG, "onReceiveIntent " + action);
-
- if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
- nm.cancel(SDCARD_STATUS);
-
- Intent statusIntent = new Intent(Intent.ACTION_MAIN, null);
- statusIntent.setClass(context, SdCardSettings.class);
- nm.notify(SDCARD_STATUS, new Notification(context,
- android.R.drawable.stat_notify_sdcard,
- null,
- System.currentTimeMillis(),
- context.getText(R.string.sdcard_setting),
- null,
- statusIntent));
- } else if (action.equals(Intent.ACTION_MEDIA_REMOVED)) {
- nm.cancel(SDCARD_STATUS);
- } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
- nm.cancel(SDCARD_STATUS);
-
- Intent statusIntent = new Intent(Intent.ACTION_MAIN, null);
- statusIntent.setClass(context, SdCardSettings.class);
- nm.notify(SDCARD_STATUS, new Notification(context,
- android.R.drawable.stat_notify_sdcard_usb,
- null,
- System.currentTimeMillis(),
- "SD Card",
- null,
- statusIntent));
- }
- }
-}
diff --git a/src/com/android/settings/SdCardSettings.java b/src/com/android/settings/SdCardSettings.java
deleted file mode 100644
index 637babefe44..00000000000
--- a/src/com/android/settings/SdCardSettings.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.Environment;
-import android.os.IMountService;
-import android.os.ServiceManager;
-import android.os.StatFs;
-import android.text.format.Formatter;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import java.io.File;
-
-
-public class SdCardSettings extends Activity
-{
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.sdcard_settings_screen);
-
- mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-
- mRemovedLayout = findViewById(R.id.removed);
- mMountedLayout = findViewById(R.id.mounted);
- mUnmountedLayout = findViewById(R.id.unmounted);
- mScanningLayout = findViewById(R.id.scanning);
- mSharedLayout = findViewById(R.id.shared);
- mBadRemovalLayout = findViewById(R.id.bad_removal);
- mReadOnlyStatus = findViewById(R.id.read_only);
-
- mMassStorage = (CheckBox)findViewById(R.id.mass_storage);
- mMassStorage.setOnClickListener(mMassStorageListener);
-
- Button unmountButton = (Button)findViewById(R.id.sdcard_unmount);
- unmountButton.setOnClickListener(mUnmountButtonHandler);
-
- Button formatButton = (Button)findViewById(R.id.sdcard_format);
- formatButton.setOnClickListener(mFormatButtonHandler);
-
- mTotalSize = (TextView)findViewById(R.id.total);
- mUsedSize = (TextView)findViewById(R.id.used);
- mAvailableSize = (TextView)findViewById(R.id.available);
-
- // install an intent filter to receive SD card related events.
- IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_REMOVED);
- intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_SHARED);
- intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING);
- intentFilter.addAction(Intent.ACTION_MEDIA_NOFS);
- intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
- intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
- intentFilter.addDataScheme("file");
- registerReceiver(mReceiver, intentFilter);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- update();
- }
-
- private void setLayout(View layout) {
- mRemovedLayout.setVisibility(layout == mRemovedLayout ? View.VISIBLE : View.GONE);
- mMountedLayout.setVisibility(layout == mMountedLayout ? View.VISIBLE : View.GONE);
- mUnmountedLayout.setVisibility(layout == mUnmountedLayout ? View.VISIBLE : View.GONE);
- mScanningLayout.setVisibility(layout == mScanningLayout ? View.VISIBLE : View.GONE);
- mSharedLayout.setVisibility(layout == mSharedLayout ? View.VISIBLE : View.GONE);
- mBadRemovalLayout.setVisibility(layout == mBadRemovalLayout ? View.VISIBLE : View.GONE);
- }
-
- private void update() {
- try {
- mMassStorage.setChecked(mMountService.getMassStorageEnabled());
- } catch (RemoteException ex) {
- }
-
- String scanVolume = null; // this no longer exists: SystemProperties.get(MediaScanner.CURRENT_VOLUME_PROPERTY, "");
- boolean scanning = "external".equals(scanVolume);
-
- if (scanning) {
- setLayout(mScanningLayout);
- } else {
- String status = Environment.getExternalStorageState();
- boolean readOnly = false;
-
- if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
- status = Environment.MEDIA_MOUNTED;
- readOnly = true;
- }
-
- if (status.equals(Environment.MEDIA_MOUNTED)) {
- try {
- File path = Environment.getExternalStorageDirectory();
- StatFs stat = new StatFs(path.getPath());
- long blockSize = stat.getBlockSize();
- long totalBlocks = stat.getBlockCount();
- long availableBlocks = stat.getAvailableBlocks();
-
- mTotalSize.setText(formatSize(totalBlocks * blockSize));
- mUsedSize.setText(formatSize((totalBlocks - availableBlocks) * blockSize));
- mAvailableSize.setText(formatSize(availableBlocks * blockSize));
- } catch (IllegalArgumentException e) {
- // this can occur if the SD card is removed, but we haven't received the
- // ACTION_MEDIA_REMOVED Intent yet.
- status = Environment.MEDIA_REMOVED;
- }
-
- mReadOnlyStatus.setVisibility(readOnly ? View.VISIBLE : View.GONE);
- setLayout(mMountedLayout);
- } else if (status.equals(Environment.MEDIA_UNMOUNTED)) {
- setLayout(mUnmountedLayout);
- } else if (status.equals(Environment.MEDIA_REMOVED)) {
- setLayout(mRemovedLayout);
- } else if (status.equals(Environment.MEDIA_SHARED)) {
- setLayout(mSharedLayout);
- } else if (status.equals(Environment.MEDIA_BAD_REMOVAL)) {
- setLayout(mBadRemovalLayout);
- }
- }
- }
-
- private String formatSize(long size) {
- return Formatter.formatFileSize(this, size);
- }
-
- OnClickListener mMassStorageListener = new OnClickListener() {
- public void onClick(View v) {
- try {
- mMountService.setMassStorageEnabled(mMassStorage.isChecked());
- } catch (RemoteException ex) {
- }
- }
- };
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- update();
- }
- };
-
- OnClickListener mUnmountButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- try {
- mMountService.unmountMedia(Environment.getExternalStorageDirectory().toString());
- } catch (RemoteException ex) {
- }
- }
- };
-
- OnClickListener mFormatButtonHandler = new OnClickListener() {
- public void onClick(View v) {
- try {
- mMountService.formatMedia(Environment.getExternalStorageDirectory().toString());
- } catch (RemoteException ex) {
- }
- }
- };
-
-
- private int mStatus;
- private IMountService mMountService;
-
- private CheckBox mMassStorage;
-
- private TextView mTotalSize;
- private TextView mUsedSize;
- private TextView mAvailableSize;
-
- private View mRemovedLayout;
- private View mMountedLayout;
- private View mUnmountedLayout;
- private View mScanningLayout;
- private View mSharedLayout;
- private View mBadRemovalLayout;
- private View mReadOnlyStatus;
-}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index d9f49527f2f..5bc50c76f75 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -17,104 +17,101 @@
package com.android.settings;
+import java.util.ArrayList;
+import java.util.Observable;
+import java.util.Observer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.location.LocationManager;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
+import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
-import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.preference.Preference.OnPreferenceChangeListener;
import android.provider.Settings;
-import android.security.CertTool;
-import android.security.Keystore;
-import android.text.Html;
-import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.widget.LockPatternUtils;
-import android.telephony.TelephonyManager;
+import android.content.ComponentName;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Observable;
-import java.util.Observer;
+import com.authentec.AuthentecHelper;
/**
* Gesture lock pattern settings.
*/
-public class SecuritySettings extends PreferenceActivity implements
- DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
+public class SecuritySettings extends PreferenceActivity implements OnPreferenceChangeListener {
+
+ public static final String GPS_STATUS_CHANGED="com.android.settings.GPS_STATUS_CHANGED";
+
+ private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
// Lock Settings
+ private static final String PACKAGE = "com.android.settings";
+ private static final String ICC_LOCK_SETTINGS = PACKAGE + ".IccLockSettings";
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
- private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
- private static final int CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE = 55;
+ private static final String KEY_SHOW_ERROR_PATH = "show_error_path";
+ private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
+ private static final String KEY_START_DATABASE_ADMINISTRATION = "start_database_administration";
+
+ // Encrypted File Systems constants
+ private static final String PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
+ private static final String PROPERTY_EFS_TRANSITION = "persist.security.efs.trans";
- private LockPatternUtils mLockPatternUtils;
- private CheckBoxPreference mLockEnabled;
private CheckBoxPreference mVisiblePattern;
+ private CheckBoxPreference mShowErrorPath;
private CheckBoxPreference mTactileFeedback;
- private Preference mChoosePattern;
+ private Preference mStartDatabaseAdministration;
private CheckBoxPreference mShowPassword;
// Location Settings
- private static final String LOCATION_CATEGORY = "location_category";
private static final String LOCATION_NETWORK = "location_network";
private static final String LOCATION_GPS = "location_gps";
+ private static final String ASSISTED_GPS = "assisted_gps";
+ private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
+ private static final int TSM_RESULT = 195;
// Credential storage
- public static final String ACTION_ADD_CREDENTIAL =
- "android.security.ADD_CREDENTIAL";
- public static final String ACTION_UNLOCK_CREDENTIAL_STORAGE =
- "android.security.UNLOCK_CREDENTIAL_STORAGE";
- private static final String KEY_CSTOR_TYPE_NAME = "typeName";
- private static final String KEY_CSTOR_ITEM = "item";
- private static final String KEY_CSTOR_NAMESPACE = "namespace";
- private static final String KEY_CSTOR_DESCRIPTION = "description";
- private static final int CSTOR_MIN_PASSWORD_LENGTH = 8;
-
- private static final int CSTOR_INIT_DIALOG = 1;
- private static final int CSTOR_CHANGE_PASSWORD_DIALOG = 2;
- private static final int CSTOR_UNLOCK_DIALOG = 3;
- private static final int CSTOR_RESET_DIALOG = 4;
- private static final int CSTOR_NAME_CREDENTIAL_DIALOG = 5;
-
- private CstorHelper mCstorHelper = new CstorHelper();
-
- // Vendor specific
- private static final String GSETTINGS_PROVIDER = "com.google.android.providers.settings";
- private static final String USE_LOCATION = "use_location";
- private static final String KEY_DONE_USE_LOCATION = "doneLocation";
- private CheckBoxPreference mUseLocation;
- private boolean mOkClicked;
- private Dialog mUseLocationDialog;
+ private CredentialStorage mCredentialStorage = new CredentialStorage();
+
+ // Encrypted file system
+ private CheckBoxPreference mEncryptedFSEnabled;
private CheckBoxPreference mNetwork;
private CheckBoxPreference mGps;
+ private CheckBoxPreference mAssistedGps;
+
+ DevicePolicyManager mDPM;
// These provide support for receiving notification when Location Manager settings change.
// This is necessary because the Network Location Provider can change settings
// if the user does not confirm enabling the provider.
private ContentQueryMap mContentQueryMap;
+ private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+ private LockPatternUtils mLockPatternUtils;
private final class SettingsObserver implements Observer {
public void update(Observable o, Object arg) {
updateToggles();
@@ -124,27 +121,42 @@ public void update(Observable o, Object arg) {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.security_settings);
- mLockPatternUtils = new LockPatternUtils(getContentResolver());
+ mLockPatternUtils = new LockPatternUtils(this);
+
+ mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
createPreferenceHierarchy();
- mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
- mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
- mUseLocation = (CheckBoxPreference) getPreferenceScreen().findPreference(USE_LOCATION);
-
- // Vendor specific
- try {
- if (mUseLocation != null
- && getPackageManager().getPackageInfo(GSETTINGS_PROVIDER, 0) == null) {
- ((PreferenceGroup)findPreference(LOCATION_CATEGORY))
- .removePreference(mUseLocation);
+ updateToggles();
+
+ //add BT gps devices
+ ListPreference btpref = (ListPreference) findPreference("location_gps_source");
+ ArrayList entries = new ArrayList();
+ for (String e : getResources().getStringArray(R.array.location_entries_gps_source) ) {
+ entries.add(e);
+ }
+ ArrayList values = new ArrayList();
+ for (String v: getResources().getStringArray(R.array.location_values_gps_source)) {
+ values.add(v);
+ }
+ // add known bonded BT devices
+ BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if ((mBluetoothAdapter != null) && (mBluetoothAdapter.isEnabled())) {
+ for (BluetoothDevice d : mBluetoothAdapter.getBondedDevices()) {
+ String dname = d.getName() + " - " + d.getAddress();
+ entries.add(dname);
+ values.add(d.getAddress());
}
- } catch (NameNotFoundException nnfe) {
}
- updateToggles();
+ btpref.setEntries(entries.toArray(new CharSequence[entries.size()]));
+ btpref.setEntryValues(values.toArray(new CharSequence[values.size()]));
+ btpref.setDefaultValue("0");
+ btpref.setOnPreferenceChangeListener(this);
+
// listen for Location Manager settings changes
Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null,
"(" + Settings.System.NAME + "=?)",
@@ -152,51 +164,86 @@ && getPackageManager().getPackageInfo(GSETTINGS_PROVIDER, 0) == null) {
null);
mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
mContentQueryMap.addObserver(new SettingsObserver());
- boolean doneUseLocation = savedInstanceState == null
- ? false : savedInstanceState.getBoolean(KEY_DONE_USE_LOCATION, true);
- if (!doneUseLocation && (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false)
- || savedInstanceState != null)) {
- showUseLocationDialog(true);
- }
+ }
- mCstorHelper.handleCstorIntents(getIntent());
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String oldPref = Settings.System.getString(getContentResolver(),
+ Settings.Secure.EXTERNAL_GPS_BT_DEVICE);
+ String newPref = newValue == null ? "0" : (String) newValue;
+ // "0" represents the internal GPS.
+ Settings.System.putString(getContentResolver(), Settings.Secure.EXTERNAL_GPS_BT_DEVICE,
+ newPref);
+ if (!oldPref.equals(newPref) && ("0".equals(oldPref) || "0".equals(newPref)) ) {
+ LocationManager locationManager =
+ (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+ locationManager.setGPSSource(newPref);
+
+ // Show dialog to inform user that source has been switched
+ AlertDialog alertDialog = new AlertDialog.Builder(this).create();
+ alertDialog.setTitle(R.string.location_gps_source_notification_title);
+ alertDialog.setMessage(getResources().getString(R.string.location_gps_source_notification));
+ alertDialog.setButton(DialogInterface.BUTTON_POSITIVE,
+ getResources().getString(com.android.internal.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ return;
+ }
+ });
+ alertDialog.show();
+ }
+ return true;
}
+
private PreferenceScreen createPreferenceHierarchy() {
- // Root
PreferenceScreen root = this.getPreferenceScreen();
+ if (root != null) {
+ root.removeAll();
+ }
+ addPreferencesFromResource(R.xml.security_settings);
+ root = this.getPreferenceScreen();
- // Inline preferences
- PreferenceCategory inlinePrefCat = new PreferenceCategory(this);
- inlinePrefCat.setTitle(R.string.lock_settings_title);
- root.addPreference(inlinePrefCat);
+ mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
+ mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
+ mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS);
- // autolock toggle
- mLockEnabled = new LockEnabledPref(this);
- mLockEnabled.setTitle(R.string.lockpattern_settings_enable_title);
- mLockEnabled.setSummary(R.string.lockpattern_settings_enable_summary);
- mLockEnabled.setKey(KEY_LOCK_ENABLED);
- inlinePrefCat.addPreference(mLockEnabled);
+ PreferenceManager pm = getPreferenceManager();
+
+ // Lock screen
+ if (!mLockPatternUtils.isSecure()) {
+ addPreferencesFromResource(R.xml.security_settings_chooser);
+ } else {
+ switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
+ case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+ addPreferencesFromResource(R.xml.security_settings_pattern);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_FINGER:
+ addPreferencesFromResource(R.xml.security_settings_finger);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+ addPreferencesFromResource(R.xml.security_settings_pin);
+ break;
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ addPreferencesFromResource(R.xml.security_settings_password);
+ break;
+ }
+ }
+
+ // set or change current. Should be common to all unlock preference screens
+ // mSetOrChange = (PreferenceScreen) pm.findPreference(KEY_UNLOCK_SET_OR_CHANGE);
// visible pattern
- mVisiblePattern = new CheckBoxPreference(this);
- mVisiblePattern.setKey(KEY_VISIBLE_PATTERN);
- mVisiblePattern.setTitle(R.string.lockpattern_settings_enable_visible_pattern_title);
- inlinePrefCat.addPreference(mVisiblePattern);
-
- // tactile feedback
- mTactileFeedback = new CheckBoxPreference(this);
- mTactileFeedback.setKey(KEY_TACTILE_FEEDBACK_ENABLED);
- mTactileFeedback.setTitle(R.string.lockpattern_settings_enable_tactile_feedback_title);
- inlinePrefCat.addPreference(mTactileFeedback);
-
- // change pattern lock
- Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.ChooseLockPatternTutorial");
- mChoosePattern = getPreferenceManager().createPreferenceScreen(this);
- mChoosePattern.setIntent(intent);
- inlinePrefCat.addPreference(mChoosePattern);
+ mVisiblePattern = (CheckBoxPreference) pm.findPreference(KEY_VISIBLE_PATTERN);
+
+ // show error path of pattern
+ mShowErrorPath = (CheckBoxPreference) pm.findPreference(KEY_SHOW_ERROR_PATH);
+
+ // tactile feedback. Should be common to all unlock preference screens.
+ mTactileFeedback = (CheckBoxPreference) pm.findPreference(KEY_TACTILE_FEEDBACK_ENABLED);
+
+ mStartDatabaseAdministration = (Preference) findPreference(KEY_START_DATABASE_ADMINISTRATION);
int activePhoneType = TelephonyManager.getDefault().getPhoneType();
@@ -207,10 +254,7 @@ private PreferenceScreen createPreferenceHierarchy() {
.createPreferenceScreen(this);
simLockPreferences.setTitle(R.string.sim_lock_settings_category);
// Intent to launch SIM lock settings
- intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
- simLockPreferences.setIntent(intent);
-
+ simLockPreferences.setIntent(new Intent().setClassName(PACKAGE, ICC_LOCK_SETTINGS));
PreferenceCategory simLockCat = new PreferenceCategory(this);
simLockCat.setTitle(R.string.sim_lock_settings_title);
root.addPreference(simLockCat);
@@ -229,15 +273,30 @@ private PreferenceScreen createPreferenceHierarchy() {
showPassword.setPersistent(false);
passwordsCat.addPreference(showPassword);
- // Credential storage
- PreferenceCategory credStoreCat = new PreferenceCategory(this);
- credStoreCat.setTitle(R.string.cstor_settings_category);
- root.addPreference(credStoreCat);
- int s = mCstorHelper.getCstorState();
- credStoreCat.addPreference(mCstorHelper.createAccessCheckBox(s));
- credStoreCat.addPreference(mCstorHelper.createSetPasswordPreference());
- credStoreCat.addPreference(mCstorHelper.createResetPreference(s));
+ // Device policies
+ PreferenceCategory devicePoliciesCat = new PreferenceCategory(this);
+ devicePoliciesCat.setTitle(R.string.device_admin_title);
+ root.addPreference(devicePoliciesCat);
+
+ Preference deviceAdminButton = new Preference(this);
+ deviceAdminButton.setTitle(R.string.manage_device_admin);
+ deviceAdminButton.setSummary(R.string.manage_device_admin_summary);
+ Intent deviceAdminIntent = new Intent();
+ deviceAdminIntent.setClass(this, DeviceAdminSettings.class);
+ deviceAdminButton.setIntent(deviceAdminIntent);
+ devicePoliciesCat.addPreference(deviceAdminButton);
+ // Credential storage
+ PreferenceCategory credentialsCat = new PreferenceCategory(this);
+ credentialsCat.setTitle(R.string.credentials_category);
+ root.addPreference(credentialsCat);
+ mCredentialStorage.createPreferences(credentialsCat, CredentialStorage.TYPE_KEYSTORE);
+
+ // File System Encryption
+ PreferenceCategory encryptedfsCat = new PreferenceCategory(this);
+ encryptedfsCat.setTitle(R.string.encrypted_fs_category);
+ //root.addPreference(encryptedfsCat);
+ mCredentialStorage.createPreferences(encryptedfsCat, CredentialStorage.TYPE_ENCRYPTEDFS);
return root;
}
@@ -245,150 +304,113 @@ private PreferenceScreen createPreferenceHierarchy() {
protected void onResume() {
super.onResume();
- boolean patternExists = mLockPatternUtils.savedPatternExists();
- mLockEnabled.setEnabled(patternExists);
- mVisiblePattern.setEnabled(patternExists);
- mTactileFeedback.setEnabled(patternExists);
-
- mLockEnabled.setChecked(mLockPatternUtils.isLockPatternEnabled());
- mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled());
- mTactileFeedback.setChecked(mLockPatternUtils.isTactileFeedbackEnabled());
-
- int chooseStringRes = mLockPatternUtils.savedPatternExists() ?
- R.string.lockpattern_settings_change_lock_pattern :
- R.string.lockpattern_settings_choose_lock_pattern;
- mChoosePattern.setTitle(chooseStringRes);
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ if (mVisiblePattern != null) {
+ boolean visible = lockPatternUtils.isVisiblePatternEnabled();
+ mVisiblePattern.setChecked(visible);
+ if (mShowErrorPath != null) {
+ mShowErrorPath.setChecked(visible || lockPatternUtils.isShowErrorPath());
+ mShowErrorPath.setEnabled(!visible);
+ }
+ }
+ if (mTactileFeedback != null) {
+ mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
+ }
- mShowPassword
- .setChecked(Settings.System.getInt(getContentResolver(),
+ mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
- }
- @Override
- public void onStop() {
- if (mUseLocationDialog != null && mUseLocationDialog.isShowing()) {
- mUseLocationDialog.dismiss();
- }
- mUseLocationDialog = null;
- super.onStop();
- }
-
- @Override
- public void onSaveInstanceState(Bundle icicle) {
- if (mUseLocationDialog != null && mUseLocationDialog.isShowing()) {
- icicle.putBoolean(KEY_DONE_USE_LOCATION, false);
- }
- super.onSaveInstanceState(icicle);
+ mCredentialStorage.resume();
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
- final String key = preference.getKey();
- if (KEY_LOCK_ENABLED.equals(key)) {
- mLockPatternUtils.setLockPatternEnabled(isToggled(preference));
+ final String key = preference.getKey();
+ final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
+ if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
+ Intent intent = new Intent(this, ChooseLockGeneric.class);
+ startActivityForResult(intent, SET_OR_CHANGE_LOCK_METHOD_REQUEST);
+ } else if (KEY_LOCK_ENABLED.equals(key)) {
+ lockPatternUtils.setLockPatternEnabled(isToggled(preference));
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
- mLockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
+ boolean visible = isToggled(preference);
+ lockPatternUtils.setVisiblePatternEnabled(visible);
+ if (visible) {
+ lockPatternUtils.setShowErrorPath(true);
+ }
+ mShowErrorPath.setChecked(lockPatternUtils.isShowErrorPath());
+ mShowErrorPath.setEnabled(!visible);
+ } else if (KEY_SHOW_ERROR_PATH.equals(key)) {
+ lockPatternUtils.setShowErrorPath(isToggled(preference));
} else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
- mLockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
- } else if (preference == mShowPassword) {
+ lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
+ } else if (KEY_START_DATABASE_ADMINISTRATION.equals(key)) {
+ // invoke the external activity
+ Intent intent = new Intent();
+ ComponentName component = new ComponentName("com.authentec.TrueSuiteMobile",
+ "com.authentec.TrueSuiteMobile.DatabaseAdministration");
+ intent.setComponent(component);
+ intent.setAction(Intent.ACTION_MAIN);
+ startActivityForResult(intent, TSM_RESULT);
+ }else if (preference == mShowPassword) {
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
} else if (preference == mNetwork) {
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
LocationManager.NETWORK_PROVIDER, mNetwork.isChecked());
} else if (preference == mGps) {
+ boolean enabled = mGps.isChecked();
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
- LocationManager.GPS_PROVIDER, mGps.isChecked());
- } else if (preference == mUseLocation) {
- //normally called on the toggle click
- if (mUseLocation.isChecked()) {
- showUseLocationDialog(false);
- } else {
- updateUseLocation();
+ LocationManager.GPS_PROVIDER, enabled);
+
+ //{PIAF - Send update of GPS status
+ Intent gpsStatus = new Intent(GPS_STATUS_CHANGED);
+ this.sendBroadcast(gpsStatus);
+ //PIAF}
+ if (mAssistedGps != null) {
+ mAssistedGps.setEnabled(enabled);
}
+ } else if (preference == mAssistedGps) {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSISTED_GPS_ENABLED,
+ mAssistedGps.isChecked() ? 1 : 0);
}
return false;
}
- private void showPrivacyPolicy() {
- Intent intent = new Intent("android.settings.TERMS");
- startActivity(intent);
- }
-
- private void showUseLocationDialog(boolean force) {
- // Show a warning to the user that location data will be shared
- mOkClicked = false;
- if (force) {
- mUseLocation.setChecked(true);
- }
-
- CharSequence msg = getResources().getText(R.string.use_location_warning_message);
- mUseLocationDialog = new AlertDialog.Builder(this).setMessage(msg)
- .setTitle(R.string.use_location_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setPositiveButton(R.string.agree, this)
- .setNegativeButton(R.string.disagree, this)
- .show();
- ((TextView)mUseLocationDialog.findViewById(android.R.id.message))
- .setMovementMethod(LinkMovementMethod.getInstance());
- mUseLocationDialog.setOnDismissListener(this);
- }
-
/*
* Creates toggles for each available location provider
*/
private void updateToggles() {
ContentResolver res = getContentResolver();
+ boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled(
+ res, LocationManager.GPS_PROVIDER);
mNetwork.setChecked(Settings.Secure.isLocationProviderEnabled(
res, LocationManager.NETWORK_PROVIDER));
- mGps.setChecked(Settings.Secure.isLocationProviderEnabled(
- res, LocationManager.GPS_PROVIDER));
- mUseLocation.setChecked(Settings.Secure.getInt(res,
- Settings.Secure.USE_LOCATION_FOR_SERVICES, 2) == 1);
+ mGps.setChecked(gpsEnabled);
+ if (mAssistedGps != null) {
+ mAssistedGps.setChecked(Settings.Secure.getInt(res,
+ Settings.Secure.ASSISTED_GPS_ENABLED, 2) == 1);
+ mAssistedGps.setEnabled(gpsEnabled);
+ }
}
private boolean isToggled(Preference pref) {
return ((CheckBoxPreference) pref).isChecked();
}
- private void updateUseLocation() {
- boolean use = mUseLocation.isChecked();
- Settings.Secure.putInt(getContentResolver(),
- Settings.Secure.USE_LOCATION_FOR_SERVICES, use ? 1 : 0);
- }
-
-
- /**
- * For the user to disable keyguard, we first make them verify their
- * existing pattern.
- */
- private class LockEnabledPref extends CheckBoxPreference {
-
- public LockEnabledPref(Context context) {
- super(context);
- }
-
- @Override
- protected void onClick() {
- if (mLockPatternUtils.savedPatternExists() && isChecked()) {
- confirmPatternThenDisableAndClear();
- } else {
- super.onClick();
+ // The toast() function is provided to allow non-UI thread code to
+ // conveniently raise a toast...
+ private void toast(final String s)
+ {
+ runOnUiThread(new Runnable() {
+ public void run()
+ {
+ Toast.makeText(SecuritySettings.this, s, Toast.LENGTH_SHORT).show();
}
- }
- }
-
- /**
- * Launch screen to confirm the existing lock pattern.
- * @see #onActivityResult(int, int, android.content.Intent)
- */
- private void confirmPatternThenDisableAndClear() {
- final Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
- startActivityForResult(intent, CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE);
+ });
}
/**
@@ -398,640 +420,382 @@ private void confirmPatternThenDisableAndClear() {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- final boolean resultOk = resultCode == Activity.RESULT_OK;
+ if (TSM_RESULT == requestCode) {
+ // NOTE: the result has a bias of 100!
+ int iResult = resultCode - 100;
+ try {
+ switch(iResult) {
+ case AuthentecHelper.eAM_STATUS_OK:
+ // Disable the fingerprint unlock mode if all fingers have been deleted.
+ if (!mLockPatternUtils.savedFingerExists()) {
+ mLockPatternUtils.setLockFingerEnabled(false);
+ }
+ break;
- if ((requestCode == CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE)
- && resultOk) {
- mLockPatternUtils.setLockPatternEnabled(false);
- mLockPatternUtils.saveLockPattern(null);
- }
- }
+ case AuthentecHelper.eAM_STATUS_LIBRARY_NOT_AVAILABLE:
+ toast(getString(R.string.lockfinger_tsm_library_not_available_toast));
+ break;
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- //updateProviders();
- mOkClicked = true;
- } else {
- // Reset the toggle
- mUseLocation.setChecked(false);
- }
- updateUseLocation();
- }
+ case AuthentecHelper.eAM_STATUS_USER_CANCELED:
+ // Do nothing!
+ break;
- public void onDismiss(DialogInterface dialog) {
- // Assuming that onClick gets called first
- if (!mOkClicked) {
- mUseLocation.setChecked(false);
+ default:
+ toast(getString(R.string.lockfinger_dbadmin_failure_default_toast, iResult));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
- }
- @Override
- protected Dialog onCreateDialog (int id) {
- switch (id) {
- case CSTOR_INIT_DIALOG:
- case CSTOR_CHANGE_PASSWORD_DIALOG:
- return mCstorHelper.createSetPasswordDialog(id);
+ createPreferenceHierarchy();
+ }
- case CSTOR_UNLOCK_DIALOG:
- return mCstorHelper.createUnlockDialog();
+ private class CredentialStorage implements DialogInterface.OnClickListener,
+ DialogInterface.OnDismissListener, Preference.OnPreferenceChangeListener,
+ Preference.OnPreferenceClickListener {
+ private static final int MINIMUM_PASSWORD_LENGTH = 8;
- case CSTOR_RESET_DIALOG:
- return mCstorHelper.createResetDialog();
+ private static final int TYPE_KEYSTORE = 0;
+ private static final int TYPE_ENCRYPTEDFS = 1;
- case CSTOR_NAME_CREDENTIAL_DIALOG:
- return mCstorHelper.createNameCredentialDialog();
+ // Dialog identifiers
+ private static final int DLG_BASE = 0;
+ private static final int DLG_UNLOCK = DLG_BASE + 1;
+ private static final int DLG_PASSWORD = DLG_UNLOCK + 1;
+ private static final int DLG_RESET = DLG_PASSWORD + 1;
+ private static final int DLG_ENABLE_EFS = DLG_RESET + 1;
- default:
- return null;
- }
- }
+ private KeyStore mKeyStore = KeyStore.getInstance();
+ private int mState;
+ private boolean mSubmit = false;
+ private boolean mExternal = false;
- private class CstorHelper implements DialogInterface.OnClickListener,
- DialogInterface.OnDismissListener,
- DialogInterface.OnCancelListener {
- private Keystore mKeystore = Keystore.getInstance();
- private View mView;
- private int mDialogId;
- private boolean mConfirm = true;
+ private boolean mWillEnableEncryptedFS;
+ private int mShowingDialog = 0;
+ // Key Store controls
private CheckBoxPreference mAccessCheckBox;
+ private Preference mInstallButton;
+ private Preference mPasswordButton;
private Preference mResetButton;
- private Intent mSpecialIntent;
- private CstorAddCredentialHelper mCstorAddCredentialHelper;
-
- void handleCstorIntents(Intent intent) {
- if (intent == null) return;
- String action = intent.getAction();
-
- if (ACTION_ADD_CREDENTIAL.equals(action)) {
- mCstorAddCredentialHelper = new CstorAddCredentialHelper(intent);
- showCstorDialog(CSTOR_NAME_CREDENTIAL_DIALOG);
- } else if (ACTION_UNLOCK_CREDENTIAL_STORAGE.equals(action)) {
- mSpecialIntent = intent;
- showCstorDialog(mCstorHelper.isCstorInitialized()
- ? CSTOR_UNLOCK_DIALOG
- : CSTOR_INIT_DIALOG);
- }
- }
- private void showCstorDialog(int dialogId) {
- mDialogId = dialogId;
- showDialog(dialogId);
-
- if (dialogId == CSTOR_NAME_CREDENTIAL_DIALOG) {
- // set mView back as mView may be replaced by CSTOR_INIT_DIALOG
- // or CSTOR_UNLOCK_DIALOG
- mView = mCstorAddCredentialHelper.mView;
- }
- }
-
- private int getCstorState() {
- return mKeystore.getState();
- }
+ // Encrypted file system controls
+ private CheckBoxPreference mEncryptedFSEnabled;
- private boolean isCstorUnlocked() {
- return (mKeystore.getState() == Keystore.UNLOCKED);
- }
+ void resume() {
+ mState = mKeyStore.test();
+ updatePreferences(mState);
- private boolean isCstorInitialized() {
- return (mKeystore.getState() != Keystore.UNINITIALIZED);
+ Intent intent = getIntent();
+ if (!mExternal && intent != null &&
+ Credentials.UNLOCK_ACTION.equals(intent.getAction())) {
+ mExternal = true;
+ if (mState == KeyStore.UNINITIALIZED) {
+ showPasswordDialog();
+ } else if (mState == KeyStore.LOCKED) {
+ showUnlockDialog();
+ } else {
+ finish();
+ }
+ }
}
- private void lockCstor() {
- mKeystore.lock();
- mAccessCheckBox.setChecked(false);
+ private void initialize(String password) {
+ mKeyStore.password(password);
+ updatePreferences(KeyStore.NO_ERROR);
}
- private int unlockCstor(String passwd) {
- int ret = mKeystore.unlock(passwd);
- if (ret == -1) resetCstor();
- if (ret == 0) {
- Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled,
- Toast.LENGTH_SHORT).show();
- }
- return ret;
+ private void reset() {
+ mKeyStore.reset();
+ updatePreferences(KeyStore.UNINITIALIZED);
}
- private int changeCstorPassword(String oldPasswd, String newPasswd) {
- int ret = mKeystore.changePassword(oldPasswd, newPasswd);
- if (ret == -1) resetCstor();
- return ret;
+ private void lock() {
+ mKeyStore.lock();
+ updatePreferences(KeyStore.LOCKED);
}
- private void initCstor(String passwd) {
- mKeystore.setPassword(passwd);
- enablePreferences(true);
- mAccessCheckBox.setChecked(true);
- Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled,
- Toast.LENGTH_SHORT).show();
+ private int unlock(String password) {
+ mKeyStore.unlock(password);
+ return mKeyStore.getLastError();
}
- private void resetCstor() {
- mKeystore.reset();
- enablePreferences(false);
- mAccessCheckBox.setChecked(false);
- Toast.makeText(SecuritySettings.this, R.string.cstor_is_reset,
- Toast.LENGTH_LONG).show();
+ private int changePassword(String oldPassword, String newPassword) {
+ mKeyStore.password(oldPassword, newPassword);
+ return mKeyStore.getLastError();
}
- private boolean addCredential() {
- if (mCstorAddCredentialHelper.saveToStorage() != 0) {
- // set mView back as mView may be replaced by CSTOR_INIT_DIALOG
- // or CSTOR_UNLOCK_DIALOG
- mView = mCstorAddCredentialHelper.mView;
- if (mCstorAddCredentialHelper.isPkcs12Keystore()) {
- showError(R.string.cstor_password_error);
+ public boolean onPreferenceChange(Preference preference, Object value) {
+ if (preference == mAccessCheckBox) {
+ if ((Boolean) value) {
+ showUnlockDialog();
} else {
- showError(R.string.cstor_storage_error);
+ lock();
}
- Log.d("CSTOR", "failed to add credential");
- return false;
+ return true;
+ } else if (preference == mEncryptedFSEnabled) {
+ Boolean bval = (Boolean)value;
+ mWillEnableEncryptedFS = bval.booleanValue();
+ showSwitchEncryptedFSDialog();
}
- Log.d("CSTOR", "credential is added: "
- + mCstorAddCredentialHelper.getName());
- String formatString =
- getString(R.string.cstor_is_added);
- String message = String.format(formatString,
- mCstorAddCredentialHelper.getName());
- Toast.makeText(SecuritySettings.this, message,
- Toast.LENGTH_LONG).show();
return true;
}
- public void onCancel(DialogInterface dialog) {
- if (mCstorAddCredentialHelper == null) return;
-
- switch (mDialogId) {
- case CSTOR_INIT_DIALOG:
- case CSTOR_UNLOCK_DIALOG:
- Toast.makeText(SecuritySettings.this,
- R.string.cstor_unable_to_save_cert,
- Toast.LENGTH_LONG).show();
- break;
-
- case CSTOR_NAME_CREDENTIAL_DIALOG:
- Toast.makeText(SecuritySettings.this,
- R.string.cstor_cert_not_saved,
- Toast.LENGTH_LONG).show();
- break;
- }
- mCstorAddCredentialHelper = null;
- finish();
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_NEGATIVE) {
- onCancel(dialog);
- return;
- }
-
- switch (mDialogId) {
- case CSTOR_INIT_DIALOG:
- case CSTOR_CHANGE_PASSWORD_DIALOG:
- mConfirm = checkPasswords((Dialog) dialog);
- break;
-
- case CSTOR_UNLOCK_DIALOG:
- mConfirm = checkUnlockPassword((Dialog) dialog);
- break;
-
- case CSTOR_RESET_DIALOG:
- resetCstor();
- break;
-
- case CSTOR_NAME_CREDENTIAL_DIALOG:
- mConfirm = checkAddCredential();
- break;
- }
- }
-
- public void onDismiss(DialogInterface dialog) {
- if (!mConfirm) {
- mConfirm = true;
- showCstorDialog(mDialogId);
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference == mInstallButton) {
+ Credentials.getInstance().installFromSdCard(SecuritySettings.this);
+ } else if (preference == mPasswordButton) {
+ showPasswordDialog();
+ } else if (preference == mResetButton) {
+ showResetDialog();
} else {
- if (mDialogId == CSTOR_UNLOCK_DIALOG) {
- mAccessCheckBox.setChecked(isCstorUnlocked());
- }
-
- if (mCstorAddCredentialHelper != null) {
- if (!isCstorInitialized()) {
- showCstorDialog(CSTOR_INIT_DIALOG);
- } else if (!isCstorUnlocked()) {
- showCstorDialog(CSTOR_UNLOCK_DIALOG);
- } else {
- if (addCredential()) {
- // succeeded
- finish();
- } else {
- // failed
- if (mDialogId != CSTOR_NAME_CREDENTIAL_DIALOG) {
- removeDialog(mDialogId);
- }
- showCstorDialog(CSTOR_NAME_CREDENTIAL_DIALOG);
- }
- }
- return;
- } else if (mSpecialIntent != null) {
- finish();
- }
- removeDialog(mDialogId);
+ return false;
}
+ return true;
}
- private void showResetWarning(int count) {
- TextView v = showError(count <= 3
- ? R.string.cstor_password_error_reset_warning
- : R.string.cstor_password_error);
- if (count <= 3) {
- if (count == 1) {
- v.setText(R.string.cstor_password_error_reset_warning);
+ public void onClick(DialogInterface dialog, int button) {
+ if (mShowingDialog != DLG_ENABLE_EFS) {
+ mSubmit = (button == DialogInterface.BUTTON_POSITIVE);
+ if (button == DialogInterface.BUTTON_NEUTRAL) {
+ reset();
+ }
+ } else {
+ if (button == DialogInterface.BUTTON_POSITIVE) {
+ Intent intent = new Intent("android.intent.action.MASTER_CLEAR");
+ intent.putExtra("enableEFS", mWillEnableEncryptedFS);
+ sendBroadcast(intent);
+ updatePreferences(mState);
+ } else if (button == DialogInterface.BUTTON_NEGATIVE) {
+ // Cancel action
+ Toast.makeText(SecuritySettings.this, R.string.encrypted_fs_cancel_confirm,
+ Toast.LENGTH_SHORT).show();
+ updatePreferences(mState);
} else {
- String format = getString(
- R.string.cstor_password_error_reset_warning_plural);
- v.setText(String.format(format, count));
+ // Unknown - should not happen
+ return;
}
}
}
- private boolean checkAddCredential() {
- hideError();
-
- String name = getText(R.id.cstor_credential_name);
- if (TextUtils.isEmpty(name)) {
- showError(R.string.cstor_name_empty_error);
- return false;
- }
-
- for (int i = 0, len = name.length(); i < len; i++) {
- if (!Character.isLetterOrDigit(name.charAt(i))) {
- showError(R.string.cstor_name_char_error);
- return false;
- }
- }
-
- mCstorAddCredentialHelper.setName(name);
-
- if (mCstorAddCredentialHelper.isPkcs12Keystore()) {
- String password = getText(R.id.cstor_credential_password);
- if (TextUtils.isEmpty(password)) {
- showError(R.string.cstor_password_empty_error);
- return false;
+ public void onDismiss(DialogInterface dialog) {
+ if (mSubmit && !isFinishing()) {
+ mSubmit = false;
+ if (!checkPassword((Dialog) dialog)) {
+ ((Dialog) dialog).show();
+ return;
}
-
- mCstorAddCredentialHelper.setPassword(password);
}
-
- return true;
- }
-
- // returns true if the password is long enough and does not contain
- // characters that we don't like
- private boolean verifyPassword(String passwd) {
- if (passwd == null) {
- showError(R.string.cstor_passwords_empty_error);
- return false;
- } else if ((passwd.length() < CSTOR_MIN_PASSWORD_LENGTH)
- || passwd.contains(" ")) {
- showError(R.string.cstor_password_verification_error);
- return false;
- } else {
- return true;
+ updatePreferences(mState);
+ if (mExternal) {
+ finish();
}
}
- // returns true if the password is ok
- private boolean checkUnlockPassword(Dialog d) {
- hideError();
-
- String passwd = getText(R.id.cstor_password);
- if (TextUtils.isEmpty(passwd)) {
- showError(R.string.cstor_password_empty_error);
- return false;
- }
+ // Return true if there is no error.
+ private boolean checkPassword(Dialog dialog) {
+ String oldPassword = getText(dialog, R.id.old_password);
+ String newPassword = getText(dialog, R.id.new_password);
+ String confirmPassword = getText(dialog, R.id.confirm_password);
- int count = unlockCstor(passwd);
- if (count > 0) {
- showResetWarning(count);
+ if (oldPassword != null && oldPassword.length() == 0) {
+ showError(dialog, R.string.credentials_password_empty);
return false;
- } else {
- // done or reset
+ } else if (newPassword == null) {
+ return !checkError(dialog, unlock(oldPassword));
+ } else if (newPassword.length() == 0 || confirmPassword.length() == 0) {
+ showError(dialog, R.string.credentials_passwords_empty);
+ } else if (newPassword.length() < MINIMUM_PASSWORD_LENGTH) {
+ showError(dialog, R.string.credentials_password_too_short);
+ } else if (!newPassword.equals(confirmPassword)) {
+ showError(dialog, R.string.credentials_passwords_mismatch);
+ } else if (oldPassword == null) {
+ initialize(newPassword);
return true;
+ } else {
+ return !checkError(dialog, changePassword(oldPassword, newPassword));
}
+ return false;
}
- // returns true if the passwords are ok
- private boolean checkPasswords(Dialog d) {
- hideError();
-
- String oldPasswd = getText(R.id.cstor_old_password);
- String newPasswd = getText(R.id.cstor_new_password);
- String confirmPasswd = getText(R.id.cstor_confirm_password);
-
- if ((mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG)
- && TextUtils.isEmpty(oldPasswd)) {
- showError(R.string.cstor_password_empty_error);
+ // Return false if there is no error.
+ private boolean checkError(Dialog dialog, int error) {
+ if (error == KeyStore.NO_ERROR) {
+ updatePreferences(KeyStore.NO_ERROR);
return false;
}
-
- if (TextUtils.isEmpty(newPasswd)
- && TextUtils.isEmpty(confirmPasswd)) {
- showError(R.string.cstor_passwords_empty_error);
+ if (error == KeyStore.UNINITIALIZED) {
+ updatePreferences(KeyStore.UNINITIALIZED);
return false;
}
-
- if (!verifyPassword(newPasswd)) {
- return false;
- } else if (!newPasswd.equals(confirmPasswd)) {
- showError(R.string.cstor_passwords_error);
+ if (error < KeyStore.WRONG_PASSWORD) {
return false;
}
-
- if (mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG) {
- int count = changeCstorPassword(oldPasswd, newPasswd);
- if (count > 0) {
- showResetWarning(count);
- return false;
- } else {
- // done or reset
- return true;
- }
+ int count = error - KeyStore.WRONG_PASSWORD + 1;
+ if (count > 3) {
+ showError(dialog, R.string.credentials_wrong_password);
+ } else if (count == 1) {
+ showError(dialog, R.string.credentials_reset_warning);
} else {
- initCstor(newPasswd);
- return true;
+ showError(dialog, R.string.credentials_reset_warning_plural, count);
}
+ return true;
}
- private TextView showError(int messageId) {
- TextView v = (TextView) mView.findViewById(R.id.cstor_error);
- v.setText(messageId);
- if (v != null) v.setVisibility(View.VISIBLE);
- return v;
- }
-
- private void hide(int viewId) {
- View v = mView.findViewById(viewId);
- if (v != null) v.setVisibility(View.GONE);
- }
-
- private void hideError() {
- hide(R.id.cstor_error);
- }
-
- private String getText(int viewId) {
- return ((TextView) mView.findViewById(viewId)).getText().toString();
- }
-
- private void setText(int viewId, String text) {
- TextView v = (TextView) mView.findViewById(viewId);
- if (v != null) v.setText(text);
+ private String getText(Dialog dialog, int viewId) {
+ TextView view = (TextView) dialog.findViewById(viewId);
+ return (view == null || view.getVisibility() == View.GONE) ? null :
+ view.getText().toString();
}
- private void setText(int viewId, int textId) {
- TextView v = (TextView) mView.findViewById(viewId);
- if (v != null) v.setText(textId);
+ private void showError(Dialog dialog, int stringId, Object... formatArgs) {
+ TextView view = (TextView) dialog.findViewById(R.id.error);
+ if (view != null) {
+ if (formatArgs == null || formatArgs.length == 0) {
+ view.setText(stringId);
+ } else {
+ view.setText(dialog.getContext().getString(stringId, formatArgs));
+ }
+ view.setVisibility(View.VISIBLE);
+ }
}
- private void enablePreferences(boolean enabled) {
- mAccessCheckBox.setEnabled(enabled);
- mResetButton.setEnabled(enabled);
+ private void createPreferences(PreferenceCategory category, int type) {
+ switch(type) {
+ case TYPE_KEYSTORE:
+ mAccessCheckBox = new CheckBoxPreference(SecuritySettings.this);
+ mAccessCheckBox.setTitle(R.string.credentials_access);
+ mAccessCheckBox.setSummary(R.string.credentials_access_summary);
+ mAccessCheckBox.setOnPreferenceChangeListener(this);
+ category.addPreference(mAccessCheckBox);
+
+ mInstallButton = new Preference(SecuritySettings.this);
+ mInstallButton.setTitle(R.string.credentials_install_certificates);
+ mInstallButton.setSummary(R.string.credentials_install_certificates_summary);
+ mInstallButton.setOnPreferenceClickListener(this);
+ category.addPreference(mInstallButton);
+
+ mPasswordButton = new Preference(SecuritySettings.this);
+ mPasswordButton.setTitle(R.string.credentials_set_password);
+ mPasswordButton.setSummary(R.string.credentials_set_password_summary);
+ mPasswordButton.setOnPreferenceClickListener(this);
+ category.addPreference(mPasswordButton);
+
+ mResetButton = new Preference(SecuritySettings.this);
+ mResetButton.setTitle(R.string.credentials_reset);
+ mResetButton.setSummary(R.string.credentials_reset_summary);
+ mResetButton.setOnPreferenceClickListener(this);
+ category.addPreference(mResetButton);
+ break;
+
+ case TYPE_ENCRYPTEDFS:
+ mEncryptedFSEnabled = new CheckBoxPreference(SecuritySettings.this);
+ mEncryptedFSEnabled.setTitle(R.string.encrypted_fs_enable);
+ mEncryptedFSEnabled.setSummary(R.string.encrypted_fs_enable_summary);
+ mEncryptedFSEnabled.setOnPreferenceChangeListener(this);
+ // category.addPreference(mEncryptedFSEnabled);
+ break;
+ }
}
- private Preference createAccessCheckBox(int state) {
- CheckBoxPreference pref = new CheckBoxPreference(
- SecuritySettings.this);
- pref.setTitle(R.string.cstor_access_title);
- pref.setSummary(R.string.cstor_access_summary);
- pref.setEnabled(state != Keystore.UNINITIALIZED);
- pref.setChecked(state == Keystore.UNLOCKED);
- pref.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(
- Preference pref, Object value) {
- if (((Boolean) value)) {
- showCstorDialog(CSTOR_UNLOCK_DIALOG);
- } else {
- lockCstor();
- }
- return true;
- }
- });
- mAccessCheckBox = pref;
- return pref;
- }
+ private void updatePreferences(int state) {
+ mAccessCheckBox.setChecked(state == KeyStore.NO_ERROR);
+ boolean encFSEnabled = SystemProperties.getBoolean(PROPERTY_EFS_ENABLED,
+ false);
+ mResetButton.setEnabled((!encFSEnabled) && (state != KeyStore.UNINITIALIZED));
+ mAccessCheckBox.setEnabled((state != KeyStore.UNINITIALIZED) && (!encFSEnabled));
- private Preference createSetPasswordPreference() {
- Preference pref = new Preference(SecuritySettings.this);
- pref.setTitle(R.string.cstor_set_passwd_title);
- pref.setSummary(R.string.cstor_set_passwd_summary);
- pref.setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference pref) {
- showCstorDialog(isCstorInitialized()
- ? CSTOR_CHANGE_PASSWORD_DIALOG
- : CSTOR_INIT_DIALOG);
- return true;
- }
- });
- return pref;
- }
+ // Encrypted File system preferences
+ mEncryptedFSEnabled.setChecked(encFSEnabled);
- private Preference createResetPreference(int state) {
- Preference pref = new Preference(SecuritySettings.this);
- pref.setTitle(R.string.cstor_reset_title);
- pref.setSummary(R.string.cstor_reset_summary);
- pref.setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference pref) {
- showCstorDialog(CSTOR_RESET_DIALOG);
- return true;
- }
- });
- pref.setEnabled(state != Keystore.UNINITIALIZED);
- mResetButton = pref;
- return pref;
+ // Show a toast message if the state is changed.
+ if (mState == state) {
+ return;
+ } else if (state == KeyStore.NO_ERROR) {
+ Toast.makeText(SecuritySettings.this, R.string.credentials_enabled,
+ Toast.LENGTH_SHORT).show();
+ } else if (state == KeyStore.UNINITIALIZED) {
+ Toast.makeText(SecuritySettings.this, R.string.credentials_erased,
+ Toast.LENGTH_SHORT).show();
+ } else if (state == KeyStore.LOCKED) {
+ Toast.makeText(SecuritySettings.this, R.string.credentials_disabled,
+ Toast.LENGTH_SHORT).show();
+ }
+ mState = state;
}
- private Dialog createUnlockDialog() {
- mView = View.inflate(SecuritySettings.this,
- R.layout.cstor_unlock_dialog_view, null);
- hideError();
+ private void showUnlockDialog() {
+ View view = View.inflate(SecuritySettings.this,
+ R.layout.credentials_unlock_dialog, null);
- // show extra hint only when the action comes from outside
- if ((mSpecialIntent == null)
- && (mCstorAddCredentialHelper == null)) {
- hide(R.id.cstor_access_dialog_hint_from_action);
+ // Show extra hint only when the action comes from outside.
+ if (mExternal) {
+ view.findViewById(R.id.hint).setVisibility(View.VISIBLE);
}
- Dialog d = new AlertDialog.Builder(SecuritySettings.this)
- .setView(mView)
- .setTitle(R.string.cstor_access_dialog_title)
+ Dialog dialog = new AlertDialog.Builder(SecuritySettings.this)
+ .setView(view)
+ .setTitle(R.string.credentials_unlock)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this)
- .setOnCancelListener(this)
.create();
- d.setOnDismissListener(this);
- return d;
+ dialog.setOnDismissListener(this);
+ mShowingDialog = DLG_UNLOCK;
+ dialog.show();
}
- private Dialog createSetPasswordDialog(int id) {
- mView = View.inflate(SecuritySettings.this,
- R.layout.cstor_set_password_dialog_view, null);
- hideError();
-
- // show extra hint only when the action comes from outside
- if ((mSpecialIntent != null)
- || (mCstorAddCredentialHelper != null)) {
- setText(R.id.cstor_first_time_hint,
- R.string.cstor_first_time_hint_from_action);
- }
+ private void showPasswordDialog() {
+ View view = View.inflate(SecuritySettings.this,
+ R.layout.credentials_password_dialog, null);
- switch (id) {
- case CSTOR_INIT_DIALOG:
- mView.findViewById(R.id.cstor_old_password_block)
- .setVisibility(View.GONE);
- break;
-
- case CSTOR_CHANGE_PASSWORD_DIALOG:
- mView.findViewById(R.id.cstor_first_time_hint)
- .setVisibility(View.GONE);
- break;
-
- default:
- throw new RuntimeException(
- "Unknown dialog id: " + mDialogId);
+ if (mState == KeyStore.UNINITIALIZED) {
+ view.findViewById(R.id.hint).setVisibility(View.VISIBLE);
+ } else {
+ view.findViewById(R.id.old_password_prompt).setVisibility(View.VISIBLE);
+ view.findViewById(R.id.old_password).setVisibility(View.VISIBLE);
}
- Dialog d = new AlertDialog.Builder(SecuritySettings.this)
- .setView(mView)
- .setTitle(R.string.cstor_set_passwd_dialog_title)
+ Dialog dialog = new AlertDialog.Builder(SecuritySettings.this)
+ .setView(view)
+ .setTitle(R.string.credentials_set_password)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this)
- .setOnCancelListener(this)
.create();
- d.setOnDismissListener(this);
- return d;
+ dialog.setOnDismissListener(this);
+ mShowingDialog = DLG_PASSWORD;
+ dialog.show();
}
- private Dialog createResetDialog() {
- return new AlertDialog.Builder(SecuritySettings.this)
+ private void showResetDialog() {
+ mShowingDialog = DLG_RESET;
+ new AlertDialog.Builder(SecuritySettings.this)
.setTitle(android.R.string.dialog_alert_title)
.setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.cstor_reset_hint)
- .setPositiveButton(getString(android.R.string.ok), this)
+ .setMessage(R.string.credentials_reset_hint)
+ .setNeutralButton(getString(android.R.string.ok), this)
.setNegativeButton(getString(android.R.string.cancel), this)
- .create();
+ .create().show();
}
- private Dialog createNameCredentialDialog() {
- mView = View.inflate(SecuritySettings.this,
- R.layout.cstor_name_credential_dialog_view, null);
- if (mCstorAddCredentialHelper != null) {
- mCstorAddCredentialHelper.mView = mView;
- }
+ private void showSwitchEncryptedFSDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(SecuritySettings.this)
+ .setCancelable(false)
+ .setTitle(R.string.encrypted_fs_alert_dialog_title);
- hideError();
- if (!mCstorAddCredentialHelper.isPkcs12Keystore()) {
- hide(R.id.cstor_credential_password_container);
- }
-
- setText(R.id.cstor_credential_name_title,
- R.string.cstor_credential_name);
- setText(R.id.cstor_credential_info_title,
- R.string.cstor_credential_info);
- setText(R.id.cstor_credential_info,
- mCstorAddCredentialHelper.getDescription().toString());
-
- Dialog d = new AlertDialog.Builder(SecuritySettings.this)
- .setView(mView)
- .setTitle(R.string.cstor_name_credential_dialog_title)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, this)
- .setOnCancelListener(this)
- .create();
- d.setOnDismissListener(this);
- return d;
- }
- }
-
- private class CstorAddCredentialHelper {
- private String mTypeName;
- private List mItemList;
- private List mNamespaceList;
- private String mDescription;
- private String mName;
- private String mPassword;
- private View mView;
-
- CstorAddCredentialHelper(Intent intent) {
- parse(intent);
- }
-
- String getTypeName() {
- return mTypeName;
- }
-
- boolean isPkcs12Keystore() {
- return CertTool.TITLE_PKCS12_KEYSTORE.equals(mTypeName);
- }
-
- CharSequence getDescription() {
- return Html.fromHtml(mDescription);
- }
-
- void setName(String name) {
- mName = name;
- }
-
- String getName() {
- return mName;
- }
-
- void setPassword(String password) {
- mPassword = password;
- }
-
- String getPassword() {
- return mPassword;
- }
-
- int saveToStorage() {
- if (isPkcs12Keystore()) {
- return CertTool.getInstance().addPkcs12Keystore(
- mItemList.get(0), mPassword, mName);
+ mShowingDialog = DLG_ENABLE_EFS;
+ if (mWillEnableEncryptedFS) {
+ builder.setMessage(R.string.encrypted_fs_enable_dialog)
+ .setPositiveButton(R.string.encrypted_fs_enable_button, this)
+ .setNegativeButton(R.string.encrypted_fs_cancel_button, this)
+ .create().show();
} else {
- Keystore ks = Keystore.getInstance();
- for (int i = 0, count = mItemList.size(); i < count; i++) {
- byte[] blob = mItemList.get(i);
- int ret = ks.put(mNamespaceList.get(i), mName,
- new String(blob));
- if (ret != 0) return ret;
- }
- }
- return 0;
- }
-
- private void parse(Intent intent) {
- mTypeName = intent.getStringExtra(KEY_CSTOR_TYPE_NAME);
- mItemList = new ArrayList();
- mNamespaceList = new ArrayList();
- for (int i = 0; ; i++) {
- byte[] blob = intent.getByteArrayExtra(KEY_CSTOR_ITEM + i);
- if (blob == null) break;
- mItemList.add(blob);
- mNamespaceList.add(intent.getStringExtra(
- KEY_CSTOR_NAMESPACE + i));
- }
-
- // build description string
- StringBuilder sb = new StringBuilder();
- for (int i = 0; ; i++) {
- String s = intent.getStringExtra(KEY_CSTOR_DESCRIPTION + i);
- if (s == null) break;
- sb.append(s).append(" ");
+ builder.setMessage(R.string.encrypted_fs_disable_dialog)
+ .setPositiveButton(R.string.encrypted_fs_disable_button, this)
+ .setNegativeButton(R.string.encrypted_fs_cancel_button, this)
+ .create().show();
}
- mDescription = sb.toString();
}
}
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 4f888ff2375..c094cb0f8d5 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -16,33 +16,72 @@
package com.android.settings;
+import android.net.sip.SipManager;
import android.os.Bundle;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ActivityInfo;
+import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
-import android.provider.Settings.System;
+import android.telephony.TelephonyManager;
+import android.content.pm.PackageManager;
public class Settings extends PreferenceActivity {
private static final String KEY_PARENT = "parent";
private static final String KEY_CALL_SETTINGS = "call_settings";
private static final String KEY_SYNC_SETTINGS = "sync_settings";
- private static final String KEY_SEARCH_SETTINGS = "search_settings";
+ private static final String KEY_DOCK_SETTINGS = "dock_settings";
+ private static final String KEY_DEVICE_SETTINGS = "device_settings";
+ private static final String KEY_LAUNCHER = "launcher_settings";
+
+ private Preference mLauncherSettings;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+
addPreferencesFromResource(R.xml.settings);
-
+
+ int activePhoneType = TelephonyManager.getDefault().getPhoneType();
+
PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_SYNC_SETTINGS, 0);
- Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_SEARCH_SETTINGS, 0);
+ Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_LAUNCHER, 0);
+ Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_DEVICE_SETTINGS, 0);
+ mLauncherSettings = parent.findPreference(KEY_LAUNCHER);
+
+ Preference dockSettings = parent.findPreference(KEY_DOCK_SETTINGS);
+ if (getResources().getBoolean(R.bool.has_dock_settings) == false && dockSettings != null) {
+ parent.removePreference(dockSettings);
+ }
}
-
+
@Override
protected void onResume() {
super.onResume();
- findPreference(KEY_CALL_SETTINGS).setEnabled(!AirplaneModeEnabler.isAirplaneModeOn(this));
+ findPreference(KEY_CALL_SETTINGS).setEnabled(
+ !AirplaneModeEnabler.isAirplaneModeOn(this)
+ || SipManager.isVoipSupported(this));
+
+ Intent intent = new Intent();
+ intent.setAction("android.intent.action.MAIN");
+ intent.addCategory("android.intent.category.HOME");
+
+ PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
+
+ ActivityInfo a = getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY).activityInfo;
+ if (a != null && a.name.equals("com.android.launcher.Launcher") && (a.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ){
+ if ( parent.findPreference(KEY_LAUNCHER) == null){
+ parent.addPreference(mLauncherSettings);
+ }
+ } else {
+ if ( parent.findPreference(KEY_LAUNCHER) != null){
+ parent.removePreference(mLauncherSettings);
+ }
+ }
}
}
diff --git a/src/com/android/settings/SettingsCMLicenseActivity.java b/src/com/android/settings/SettingsCMLicenseActivity.java
new file mode 100644
index 00000000000..8d42123fd86
--- /dev/null
+++ b/src/com/android/settings/SettingsCMLicenseActivity.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.Log;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.zip.GZIPInputStream;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+/**
+ * The "dialog" that shows from "License" in the Settings app.
+ */
+public class SettingsCMLicenseActivity extends AlertActivity {
+
+ private static final String TAG = "SettingsCMLicenseActivity";
+ private static final boolean LOGV = false || Config.LOGV;
+
+ private static final String DEFAULT_LICENSE_PATH = "/system/etc/CM-NOTICE.html.gz";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String fileName = DEFAULT_LICENSE_PATH;
+ if (TextUtils.isEmpty(fileName)) {
+ Log.e(TAG, "The system property for the license file is empty.");
+ showErrorAndFinish();
+ return;
+ }
+
+ InputStreamReader inputReader = null;
+ StringBuilder data = null;
+ try {
+ data = new StringBuilder(2048);
+ char tmp[] = new char[2048];
+ int numRead;
+ if (fileName.endsWith(".gz")) {
+ inputReader = new InputStreamReader(
+ new GZIPInputStream(new FileInputStream(fileName)));
+ } else {
+ inputReader = new FileReader(fileName);
+ }
+ while ((numRead = inputReader.read(tmp)) >= 0) {
+ data.append(tmp, 0, numRead);
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "License HTML file not found at " + fileName, e);
+ showErrorAndFinish();
+ return;
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading license HTML file at " + fileName, e);
+ showErrorAndFinish();
+ return;
+ } finally {
+ try {
+ if (inputReader != null) {
+ inputReader.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ if (TextUtils.isEmpty(data)) {
+ Log.e(TAG, "License HTML is empty (from " + fileName + ")");
+ showErrorAndFinish();
+ return;
+ }
+
+ WebView webView = new WebView(this);
+
+ // Begin the loading. This will be done in a separate thread in WebView.
+ webView.loadDataWithBaseURL(null, data.toString(), "text/html", "utf-8", null);
+ webView.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ // Change from 'Loading...' to the real title
+ mAlert.setTitle(getString(R.string.settings_cmlicense_activity_title));
+ }
+ });
+
+ final AlertController.AlertParams p = mAlertParams;
+ p.mTitle = getString(R.string.settings_license_activity_loading);
+ p.mView = webView;
+ p.mForceInverseBackground = true;
+ setupAlert();
+ }
+
+ private void showErrorAndFinish() {
+ Toast.makeText(this, R.string.settings_license_activity_unavailable, Toast.LENGTH_LONG)
+ .show();
+ finish();
+ }
+
+}
diff --git a/src/com/android/settings/SettingsSafetyLegalActivity.java b/src/com/android/settings/SettingsSafetyLegalActivity.java
new file mode 100644
index 00000000000..368ee1dd68c
--- /dev/null
+++ b/src/com/android/settings/SettingsSafetyLegalActivity.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import android.content.DialogInterface;
+
+/**
+ * The "dialog" that shows from "Safety information" in the Settings app.
+ */
+public class SettingsSafetyLegalActivity extends AlertActivity
+ implements DialogInterface.OnCancelListener, DialogInterface.OnClickListener {
+ private static final String PROPERTY_LSAFETYLEGAL_URL = "ro.url.safetylegal";
+
+ private WebView mWebView;
+
+ private AlertDialog mErrorDialog = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String userSafetylegalUrl = SystemProperties.get(PROPERTY_LSAFETYLEGAL_URL);
+
+ final Configuration configuration = getResources().getConfiguration();
+ final String language = configuration.locale.getLanguage();
+ final String country = configuration.locale.getCountry();
+
+ String loc = String.format("locale=%s-%s", language, country);
+
+ userSafetylegalUrl = String.format("%s&%s", userSafetylegalUrl, loc);
+
+ mWebView = new WebView(this);
+
+ // Begin accessing
+ mWebView.getSettings().setJavaScriptEnabled(true);
+ if (savedInstanceState == null) {
+ mWebView.loadUrl(userSafetylegalUrl);
+ } else {
+ mWebView.restoreState(savedInstanceState);
+ }
+ mWebView.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ // Change from 'Loading...' to the real title
+ mAlert.setTitle(getString(R.string.settings_safetylegal_activity_title));
+ }
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode,
+ String description, String failingUrl) {
+ showErrorAndFinish(failingUrl);
+ }
+ });
+
+ final AlertController.AlertParams p = mAlertParams;
+ p.mTitle = getString(R.string.settings_safetylegal_activity_loading);
+ p.mView = mWebView;
+ p.mForceInverseBackground = true;
+ setupAlert();
+ }
+
+ private void showErrorAndFinish(String url) {
+ if (mErrorDialog == null) {
+ mErrorDialog = new AlertDialog.Builder(this)
+ .setTitle(R.string.settings_safetylegal_activity_title)
+ .setPositiveButton(android.R.string.ok, this)
+ .setOnCancelListener(this)
+ .setCancelable(true)
+ .create();
+ } else {
+ if (mErrorDialog.isShowing()) {
+ mErrorDialog.dismiss();
+ }
+ }
+ mErrorDialog.setMessage(getResources()
+ .getString(R.string.settings_safetylegal_activity_unreachable, url));
+ mErrorDialog.show();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ if (mErrorDialog != null) {
+ mErrorDialog.dismiss();
+ mErrorDialog = null;
+ }
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && event.getAction() == KeyEvent.ACTION_DOWN) {
+ if (mWebView.canGoBack()) {
+ mWebView.goBack();
+ return true;
+ }
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ public void onClick(DialogInterface dialog, int whichButton) {
+ finish();
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle icicle) {
+ mWebView.saveState(icicle);
+ super.onSaveInstanceState(icicle);
+ }
+}
diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundAndDisplaySettings.java
deleted file mode 100644
index 4417f240c33..00000000000
--- a/src/com/android/settings/SoundAndDisplaySettings.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static android.provider.Settings.System.COMPATIBILITY_MODE;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.os.Bundle;
-import android.os.IMountService;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceScreen;
-import android.preference.CheckBoxPreference;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.IWindowManager;
-import android.telephony.TelephonyManager;
-
-public class SoundAndDisplaySettings extends PreferenceActivity implements
- Preference.OnPreferenceChangeListener {
- private static final String TAG = "SoundAndDisplaysSettings";
-
- /** If there is no setting in the provider, use this. */
- private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000;
- private static final int FALLBACK_EMERGENCY_TONE_VALUE = 0;
-
- private static final String KEY_SILENT = "silent";
- private static final String KEY_VIBRATE = "vibrate";
- private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
- private static final String KEY_DTMF_TONE = "dtmf_tone";
- private static final String KEY_SOUND_EFFECTS = "sound_effects";
- private static final String KEY_ANIMATIONS = "animations";
- private static final String KEY_ACCELEROMETER = "accelerometer";
- private static final String KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS = "play_media_notification_sounds";
- private static final String KEY_EMERGENCY_TONE ="emergency_tone";
-
- private CheckBoxPreference mSilent;
-
- private CheckBoxPreference mPlayMediaNotificationSounds;
-
- private IMountService mMountService = null;
-
- /*
- * If we are currently in one of the silent modes (the ringer mode is set to either
- * "silent mode" or "vibrate mode"), then toggling the "Phone vibrate"
- * preference will switch between "silent mode" and "vibrate mode".
- * Otherwise, it will adjust the normal ringer mode's ring or ring+vibrate
- * setting.
- */
- private CheckBoxPreference mVibrate;
- private CheckBoxPreference mDtmfTone;
- private CheckBoxPreference mSoundEffects;
- private CheckBoxPreference mAnimations;
- private CheckBoxPreference mAccelerometer;
- private float[] mAnimationScales;
-
- private AudioManager mAudioManager;
-
- private IWindowManager mWindowManager;
-
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateState(false);
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ContentResolver resolver = getContentResolver();
- int activePhoneType = TelephonyManager.getDefault().getPhoneType();
-
- mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
-
- mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-
- addPreferencesFromResource(R.xml.sound_and_display_settings);
-
- if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) {
- // device is not CDMA, do not display CDMA emergency_tone
- getPreferenceScreen().removePreference(findPreference(KEY_EMERGENCY_TONE));
- }
-
- mSilent = (CheckBoxPreference) findPreference(KEY_SILENT);
- mPlayMediaNotificationSounds = (CheckBoxPreference) findPreference(KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS);
-
- mVibrate = (CheckBoxPreference) findPreference(KEY_VIBRATE);
- mDtmfTone = (CheckBoxPreference) findPreference(KEY_DTMF_TONE);
- mDtmfTone.setPersistent(false);
- mDtmfTone.setChecked(Settings.System.getInt(resolver,
- Settings.System.DTMF_TONE_WHEN_DIALING, 1) != 0);
- mSoundEffects = (CheckBoxPreference) findPreference(KEY_SOUND_EFFECTS);
- mSoundEffects.setPersistent(false);
- mSoundEffects.setChecked(Settings.System.getInt(resolver,
- Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0);
- mAnimations = (CheckBoxPreference) findPreference(KEY_ANIMATIONS);
- mAnimations.setPersistent(false);
- mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
- mAccelerometer.setPersistent(false);
-
- ListPreference screenTimeoutPreference =
- (ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
- screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
- resolver, SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
- screenTimeoutPreference.setOnPreferenceChangeListener(this);
-
- if (TelephonyManager.PHONE_TYPE_CDMA == activePhoneType) {
- ListPreference emergencyTonePreference =
- (ListPreference) findPreference(KEY_EMERGENCY_TONE);
- emergencyTonePreference.setValue(String.valueOf(Settings.System.getInt(
- resolver, Settings.System.EMERGENCY_TONE, FALLBACK_EMERGENCY_TONE_VALUE)));
- emergencyTonePreference.setOnPreferenceChangeListener(this);
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- updateState(true);
-
- IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
- registerReceiver(mReceiver, filter);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- unregisterReceiver(mReceiver);
- }
-
- private void updateState(boolean force) {
- final int ringerMode = mAudioManager.getRingerMode();
- final boolean silentOrVibrateMode =
- ringerMode != AudioManager.RINGER_MODE_NORMAL;
-
- if (silentOrVibrateMode != mSilent.isChecked() || force) {
- mSilent.setChecked(silentOrVibrateMode);
- }
-
- try {
- mPlayMediaNotificationSounds.setChecked(mMountService.getPlayNotificationSounds());
- } catch (RemoteException e) {
- }
-
- boolean vibrateSetting;
- if (silentOrVibrateMode) {
- vibrateSetting = ringerMode == AudioManager.RINGER_MODE_VIBRATE;
- } else {
- vibrateSetting = mAudioManager.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER)
- == AudioManager.VIBRATE_SETTING_ON;
- }
- if (vibrateSetting != mVibrate.isChecked() || force) {
- mVibrate.setChecked(vibrateSetting);
- }
-
- int silentModeStreams = Settings.System.getInt(getContentResolver(),
- Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
- boolean isAlarmInclSilentMode = (silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0;
- mSilent.setSummary(isAlarmInclSilentMode ?
- R.string.silent_mode_incl_alarm_summary :
- R.string.silent_mode_summary);
-
- boolean animations = true;
- try {
- mAnimationScales = mWindowManager.getAnimationScales();
- } catch (RemoteException e) {
- }
- if (mAnimationScales != null) {
- // We will leave the window animations alone (always set),
- // and only use this to change the transition animations.
- for (int i=1; i 0) {
- // Window animations are always on.
- mAnimationScales[0] = 1;
- }
- for (int i=1; i available = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ ArrayList active = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ ArrayList errored = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ERRORED_TETHER);
+ updateState(available.toArray(), active.toArray(), errored.toArray());
+ } else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) ||
+ intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) {
+ updateState();
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ IntentFilter filter = new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ mTetherChangeReceiver = new TetherChangeReceiver();
+ Intent intent = registerReceiver(mTetherChangeReceiver, filter);
+
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_SHARED);
+ filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+ filter.addDataScheme("file");
+ registerReceiver(mTetherChangeReceiver, filter);
+
+ if (intent != null) mTetherChangeReceiver.onReceive(this, intent);
+ mWifiApEnabler.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ unregisterReceiver(mTetherChangeReceiver);
+ mTetherChangeReceiver = null;
+ mWifiApEnabler.pause();
+ }
+
+ private void updateState() {
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ String[] available = cm.getTetherableIfaces();
+ String[] tethered = cm.getTetheredIfaces();
+ String[] errored = cm.getTetheringErroredIfaces();
+ updateState(available, tethered, errored);
+ }
+
+ private void updateState(Object[] available, Object[] tethered,
+ Object[] errored) {
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+ boolean usbTethered = false;
+ boolean usbAvailable = false;
+ int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ boolean usbErrored = false;
+ boolean massStorageActive =
+ Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
+ for (Object o : available) {
+ String s = (String)o;
+ for (String regex : mUsbRegexs) {
+ if (s.matches(regex)) {
+ usbAvailable = true;
+ if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ usbError = cm.getLastTetherError(s);
+ }
+ }
+ }
+ }
+ for (Object o : tethered) {
+ String s = (String)o;
+ for (String regex : mUsbRegexs) {
+ if (s.matches(regex)) usbTethered = true;
+ }
+ }
+ for (Object o: errored) {
+ String s = (String)o;
+ for (String regex : mUsbRegexs) {
+ if (s.matches(regex)) usbErrored = true;
+ }
+ }
+
+ if (usbTethered) {
+ mUsbTether.setSummary(R.string.usb_tethering_active_subtext);
+ mUsbTether.setEnabled(true);
+ mUsbTether.setChecked(true);
+ } else if (usbAvailable) {
+ if (usbError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ mUsbTether.setSummary(R.string.usb_tethering_available_subtext);
+ } else {
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ }
+ mUsbTether.setEnabled(true);
+ mUsbTether.setChecked(false);
+ } else if (usbErrored) {
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ mUsbTether.setEnabled(false);
+ mUsbTether.setChecked(false);
+ } else if (massStorageActive) {
+ mUsbTether.setSummary(R.string.usb_tethering_storage_active_subtext);
+ mUsbTether.setEnabled(false);
+ mUsbTether.setChecked(false);
+ } else {
+ mUsbTether.setSummary(R.string.usb_tethering_unavailable_subtext);
+ mUsbTether.setEnabled(false);
+ mUsbTether.setChecked(false);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference == mUsbTether) {
+ boolean newState = mUsbTether.isChecked();
+
+ ConnectivityManager cm =
+ (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (newState) {
+ String[] available = cm.getTetherableIfaces();
+
+ String usbIface = findIface(available, mUsbRegexs);
+ if (usbIface == null) {
+ updateState();
+ return true;
+ }
+ if (cm.tether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ mUsbTether.setChecked(false);
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ return true;
+ }
+ mUsbTether.setSummary("");
+ } else {
+ String [] tethered = cm.getTetheredIfaces();
+
+ String usbIface = findIface(tethered, mUsbRegexs);
+ if (usbIface == null) {
+ updateState();
+ return true;
+ }
+ if (cm.untether(usbIface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ mUsbTether.setSummary(R.string.usb_tethering_errored_subtext);
+ return true;
+ }
+ mUsbTether.setSummary("");
+ }
+ } else if (preference == mTetherHelp) {
+
+ showDialog(DIALOG_TETHER_HELP);
+ }
+ return false;
+ }
+
+ private String findIface(String[] ifaces, String[] regexes) {
+ for (String iface : ifaces) {
+ for (String regex : regexes) {
+ if (iface.matches(regex)) {
+ return iface;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index d3d59fa2605..89a46419819 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -22,8 +22,11 @@
import static android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY;
import static android.provider.Settings.Secure.TTS_DEFAULT_VARIANT;
import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
+import static android.provider.Settings.Secure.TTS_ENABLED_PLUGINS;
+import android.app.AlertDialog;
import android.content.ContentResolver;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -31,13 +34,17 @@
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.speech.tts.TextToSpeech;
import android.util.Log;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
@@ -48,6 +55,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private static final String TAG = "TextToSpeechSettings";
+ private static final String SYSTEM_TTS = "com.svox.pico";
private static final String KEY_TTS_PLAY_EXAMPLE = "tts_play_example";
private static final String KEY_TTS_INSTALL_DATA = "tts_install_data";
private static final String KEY_TTS_USE_DEFAULT = "toggle_use_default_tts_settings";
@@ -55,6 +63,15 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
+ private static final String KEY_TTS_DEFAULT_SYNTH = "tts_default_synth";
+
+ private static final String KEY_PLUGIN_ENABLED_PREFIX = "ENABLED_";
+ private static final String KEY_PLUGIN_SETTINGS_PREFIX = "SETTINGS_";
+
+ // TODO move default Locale values to TextToSpeech.Engine
+ private static final String DEFAULT_LANG_VAL = "eng";
+ private static final String DEFAULT_COUNTRY_VAL = "USA";
+ private static final String DEFAULT_VARIANT_VAL = "";
private static final String LOCALE_DELIMITER = "-";
@@ -66,25 +83,30 @@ public class TextToSpeechSettings extends PreferenceActivity implements
private CheckBoxPreference mUseDefaultPref = null;
private ListPreference mDefaultRatePref = null;
private ListPreference mDefaultLocPref = null;
+ private ListPreference mDefaultSynthPref = null;
private String mDefaultLanguage = null;
private String mDefaultCountry = null;
private String mDefaultLocVariant = null;
private String mDefaultEng = "";
+ private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
+
+ // Array of strings used to demonstrate TTS in the different languages.
+ private String[] mDemoStrings;
+ // Index of the current string to use for the demo.
+ private int mDemoStringIndex = 0;
private boolean mEnableDemo = false;
+ private boolean mVoicesMissing = false;
private TextToSpeech mTts = null;
+ private boolean mTtsStarted = false;
/**
* Request code (arbitrary value) for voice data check through
* startActivityForResult.
*/
private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
- /**
- * Request code (arbitrary value) for voice data installation through
- * startActivityForResult.
- */
- private static final int VOICE_DATA_INSTALLATION = 1980;
+ private static final int GET_SAMPLE_TEXT = 1983;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -92,23 +114,35 @@ protected void onCreate(Bundle savedInstanceState) {
addPreferencesFromResource(R.xml.tts_settings);
+ addEngineSpecificSettings();
+
+ mDemoStrings = getResources().getStringArray(R.array.tts_demo_strings);
+
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
mEnableDemo = false;
- initClickers();
- initDefaultSettings();
+ mTtsStarted = false;
+
+ Locale currentLocale = Locale.getDefault();
+ mDefaultLanguage = currentLocale.getISO3Language();
+ mDefaultCountry = currentLocale.getISO3Country();
+ mDefaultLocVariant = currentLocale.getVariant();
+
+ mTts = new TextToSpeech(this, this);
}
@Override
protected void onStart() {
super.onStart();
- // whenever we return to this screen, we don't know the state of the
- // system, so we have to recheck that we can play the demo, or it must be disabled.
- // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
- initClickers();
- updateWidgetState();
- checkVoiceData();
+ if (mTtsStarted){
+ // whenever we return to this screen, we don't know the state of the
+ // system, so we have to recheck that we can play the demo, or it must be disabled.
+ // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
+ initClickers();
+ updateWidgetState();
+ checkVoiceData();
+ }
}
@@ -120,6 +154,70 @@ protected void onDestroy() {
}
}
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if ((mDefaultRatePref != null) && (mDefaultRatePref.getDialog() != null)) {
+ mDefaultRatePref.getDialog().dismiss();
+ }
+ if ((mDefaultLocPref != null) && (mDefaultLocPref.getDialog() != null)) {
+ mDefaultLocPref.getDialog().dismiss();
+ }
+ if ((mDefaultSynthPref != null) && (mDefaultSynthPref.getDialog() != null)) {
+ mDefaultSynthPref.getDialog().dismiss();
+ }
+ }
+
+
+
+ private void addEngineSpecificSettings() {
+ PreferenceGroup enginesCategory = (PreferenceGroup) findPreference("tts_engines_section");
+ Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
+ ResolveInfo[] enginesArray = new ResolveInfo[0];
+ PackageManager pm = getPackageManager();
+ enginesArray = pm.queryIntentActivities(intent, 0).toArray(enginesArray);
+ for (int i = 0; i < enginesArray.length; i++) {
+ String prefKey = "";
+ final String pluginPackageName = enginesArray[i].activityInfo.packageName;
+ if (!enginesArray[i].activityInfo.packageName.equals(SYSTEM_TTS)) {
+ CheckBoxPreference chkbxPref = new CheckBoxPreference(this);
+ prefKey = KEY_PLUGIN_ENABLED_PREFIX + pluginPackageName;
+ chkbxPref.setKey(prefKey);
+ chkbxPref.setTitle(enginesArray[i].loadLabel(pm));
+ enginesCategory.addPreference(chkbxPref);
+ }
+ if (pluginHasSettings(pluginPackageName)) {
+ Preference pref = new Preference(this);
+ prefKey = KEY_PLUGIN_SETTINGS_PREFIX + pluginPackageName;
+ pref.setKey(prefKey);
+ pref.setTitle(enginesArray[i].loadLabel(pm));
+ CharSequence settingsLabel = getResources().getString(
+ R.string.tts_engine_name_settings, enginesArray[i].loadLabel(pm));
+ pref.setSummary(settingsLabel);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener(){
+ public boolean onPreferenceClick(Preference preference){
+ Intent i = new Intent();
+ i.setClassName(pluginPackageName,
+ pluginPackageName + ".EngineSettings");
+ startActivity(i);
+ return true;
+ }
+ });
+ enginesCategory.addPreference(pref);
+ }
+ }
+ }
+
+ private boolean pluginHasSettings(String pluginPackageName) {
+ PackageManager pm = getPackageManager();
+ Intent i = new Intent();
+ i.setClassName(pluginPackageName, pluginPackageName + ".EngineSettings");
+ if (pm.resolveActivity(i, PackageManager.MATCH_DEFAULT_ONLY) != null){
+ return true;
+ }
+ return false;
+ }
+
private void initClickers() {
mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
@@ -132,24 +230,27 @@ private void initClickers() {
private void initDefaultSettings() {
ContentResolver resolver = getContentResolver();
- int intVal = 0;
// Find the default TTS values in the settings, initialize and store the
// settings if they are not found.
// "Use Defaults"
+ int useDefault = 0;
mUseDefaultPref = (CheckBoxPreference) findPreference(KEY_TTS_USE_DEFAULT);
try {
- intVal = Settings.Secure.getInt(resolver, TTS_USE_DEFAULTS);
+ useDefault = Settings.Secure.getInt(resolver, TTS_USE_DEFAULTS);
} catch (SettingNotFoundException e) {
// "use default" setting not found, initialize it
- intVal = TextToSpeech.Engine.USE_DEFAULTS;
- Settings.Secure.putInt(resolver, TTS_USE_DEFAULTS, intVal);
+ useDefault = TextToSpeech.Engine.USE_DEFAULTS;
+ Settings.Secure.putInt(resolver, TTS_USE_DEFAULTS, useDefault);
}
- mUseDefaultPref.setChecked(intVal == 1);
+ mUseDefaultPref.setChecked(useDefault == 1);
mUseDefaultPref.setOnPreferenceChangeListener(this);
- // Default engine
+ // Default synthesis engine
+ mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
+ loadEngines();
+ mDefaultSynthPref.setOnPreferenceChangeListener(this);
String engine = Settings.Secure.getString(resolver, TTS_DEFAULT_SYNTH);
if (engine == null) {
// TODO move FALLBACK_TTS_DEFAULT_SYNTH to TextToSpeech
@@ -161,59 +262,19 @@ private void initDefaultSettings() {
// Default rate
mDefaultRatePref = (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
try {
- intVal = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
+ mDefaultRate = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
} catch (SettingNotFoundException e) {
// default rate setting not found, initialize it
- intVal = TextToSpeech.Engine.DEFAULT_RATE;
- Settings.Secure.putInt(resolver, TTS_DEFAULT_RATE, intVal);
+ mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
+ Settings.Secure.putInt(resolver, TTS_DEFAULT_RATE, mDefaultRate);
}
- mDefaultRatePref.setValue(String.valueOf(intVal));
+ mDefaultRatePref.setValue(String.valueOf(mDefaultRate));
mDefaultRatePref.setOnPreferenceChangeListener(this);
// Default language / country / variant : these three values map to a single ListPref
// representing the matching Locale
- String language = null;
- String country = null;
- String variant = null;
mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
- language = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
- if (language == null) {
- // the default language property isn't set, use that of the current locale
- Locale currentLocale = Locale.getDefault();
- language = currentLocale.getISO3Language();
- country = currentLocale.getISO3Country();
- variant = currentLocale.getVariant();
- Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, language);
- Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, country);
- Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
- }
- mDefaultLanguage = language;
- if (country == null) {
- // country wasn't initialized yet because a default language was found
- country = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
- if (country == null) {
- // default country setting not found, initialize it, as well as the variant;
- Locale currentLocale = Locale.getDefault();
- country = currentLocale.getISO3Country();
- variant = currentLocale.getVariant();
- Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, country);
- Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
- }
- }
- mDefaultCountry = country;
- if (variant == null) {
- // variant wasn't initialized yet because a default country was found
- variant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
- if (variant == null) {
- // default variant setting not found, initialize it
- Locale currentLocale = Locale.getDefault();
- variant = currentLocale.getVariant();
- Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
- }
- }
- mDefaultLocVariant = variant;
-
- setDefaultLocalePref(language, country, variant);
+ initDefaultLang();
mDefaultLocPref.setOnPreferenceChangeListener(this);
}
@@ -246,13 +307,38 @@ private void installVoiceData() {
PackageManager pm = getPackageManager();
Intent intent = new Intent();
intent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
List resolveInfos = pm.queryIntentActivities(intent, 0);
// query only the package that matches that of the default engine
for (int i = 0; i < resolveInfos.size(); i++) {
ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
if (mDefaultEng.equals(currentActivityInfo.packageName)) {
intent.setClassName(mDefaultEng, currentActivityInfo.name);
- this.startActivityForResult(intent, VOICE_DATA_INSTALLATION);
+ this.startActivity(intent);
+ }
+ }
+ }
+
+ /**
+ * Ask the current default engine to return a string of sample text to be
+ * spoken to the user.
+ */
+ private void getSampleText() {
+ PackageManager pm = getPackageManager();
+ Intent intent = new Intent();
+ // TODO (clchen): Replace Intent string with the actual
+ // Intent defined in the list of platform Intents.
+ intent.setAction("android.speech.tts.engine.GET_SAMPLE_TEXT");
+ intent.putExtra("language", mDefaultLanguage);
+ intent.putExtra("country", mDefaultCountry);
+ intent.putExtra("variant", mDefaultLocVariant);
+ List resolveInfos = pm.queryIntentActivities(intent, 0);
+ // query only the package that matches that of the default engine
+ for (int i = 0; i < resolveInfos.size(); i++) {
+ ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
+ if (mDefaultEng.equals(currentActivityInfo.packageName)) {
+ intent.setClassName(mDefaultEng, currentActivityInfo.name);
+ this.startActivityForResult(intent, GET_SAMPLE_TEXT);
}
}
}
@@ -263,8 +349,24 @@ private void installVoiceData() {
*/
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
- Log.v(TAG, "TTS engine for settings screen initialized.");
mEnableDemo = true;
+ if (mDefaultLanguage == null) {
+ mDefaultLanguage = Locale.getDefault().getISO3Language();
+ }
+ if (mDefaultCountry == null) {
+ mDefaultCountry = Locale.getDefault().getISO3Country();
+ }
+ if (mDefaultLocVariant == null) {
+ mDefaultLocVariant = new String();
+ }
+ mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ mTts.setSpeechRate((float)(mDefaultRate/100.0f));
+ initDefaultSettings();
+ initClickers();
+ updateWidgetState();
+ checkVoiceData();
+ mTtsStarted = true;
+ Log.v(TAG, "TTS engine for settings screen initialized.");
} else {
Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
mEnableDemo = false;
@@ -278,16 +380,114 @@ public void onInit(int status) {
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
- if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
- Log.v(TAG, "Voice data check passed");
+ if (data == null){
+ // The CHECK_TTS_DATA activity for the plugin did not run properly;
+ // disable the preview and install controls and return.
+ mEnableDemo = false;
+ mVoicesMissing = false;
+ updateWidgetState();
+ return;
+ }
+ ArrayList available =
+ data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
+ ArrayList unavailable =
+ data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
+ if ((available == null) || (unavailable == null)){
+ // The CHECK_TTS_DATA activity for the plugin did not run properly;
+ // disable the preview and install controls and return.
+ mEnableDemo = false;
+ mVoicesMissing = false;
+ updateWidgetState();
+ return;
+ }
+ if (available.size() > 0){
if (mTts == null) {
mTts = new TextToSpeech(this, this);
- mTts.setLanguage(Locale.getDefault());
+ }
+ ListPreference ttsLanguagePref =
+ (ListPreference) findPreference("tts_default_lang");
+ CharSequence[] entries = new CharSequence[available.size()];
+ CharSequence[] entryValues = new CharSequence[available.size()];
+ int selectedLanguageIndex = -1;
+ String selectedLanguagePref = mDefaultLanguage;
+ if (mDefaultCountry.length() > 0) {
+ selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER +
+ mDefaultCountry;
+ }
+ if (mDefaultLocVariant.length() > 0) {
+ selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER +
+ mDefaultLocVariant;
+ }
+ for (int i = 0; i < available.size(); i++) {
+ String[] langCountryVariant = available.get(i).split("-");
+ Locale loc = null;
+ if (langCountryVariant.length == 1){
+ loc = new Locale(langCountryVariant[0]);
+ } else if (langCountryVariant.length == 2){
+ loc = new Locale(langCountryVariant[0], langCountryVariant[1]);
+ } else if (langCountryVariant.length == 3){
+ loc = new Locale(langCountryVariant[0], langCountryVariant[1],
+ langCountryVariant[2]);
+ }
+ if (loc != null){
+ entries[i] = loc.getDisplayName();
+ entryValues[i] = available.get(i);
+ if (entryValues[i].equals(selectedLanguagePref)) {
+ selectedLanguageIndex = i;
+ }
+ }
+ }
+ ttsLanguagePref.setEntries(entries);
+ ttsLanguagePref.setEntryValues(entryValues);
+ if (selectedLanguageIndex > -1) {
+ ttsLanguagePref.setValueIndex(selectedLanguageIndex);
+ }
+ mEnableDemo = true;
+ // Make sure that the default language can be used.
+ int languageResult = mTts.setLanguage(
+ new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ if (languageResult < TextToSpeech.LANG_AVAILABLE){
+ Locale currentLocale = Locale.getDefault();
+ mDefaultLanguage = currentLocale.getISO3Language();
+ mDefaultCountry = currentLocale.getISO3Country();
+ mDefaultLocVariant = currentLocale.getVariant();
+ languageResult = mTts.setLanguage(
+ new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ // If the default Locale isn't supported, just choose the first available
+ // language so that there is at least something.
+ if (languageResult < TextToSpeech.LANG_AVAILABLE){
+ parseLocaleInfo(ttsLanguagePref.getEntryValues()[0].toString());
+ mTts.setLanguage(
+ new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ }
+ ContentResolver resolver = getContentResolver();
+ Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
+ Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
+ Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
}
} else {
- Log.v(TAG, "Voice data check failed");
mEnableDemo = false;
- updateWidgetState();
+ }
+
+ if (unavailable.size() > 0){
+ mVoicesMissing = true;
+ } else {
+ mVoicesMissing = false;
+ }
+
+ updateWidgetState();
+ } else if (requestCode == GET_SAMPLE_TEXT) {
+ if (resultCode == TextToSpeech.LANG_AVAILABLE) {
+ String sample = getString(R.string.tts_demo);
+ if ((data != null) && (data.getStringExtra("sampleText") != null)) {
+ sample = data.getStringExtra("sampleText");
+ }
+ if (mTts != null) {
+ mTts.speak(sample, TextToSpeech.QUEUE_FLUSH, null);
+ }
+ } else {
+ // TODO: Display an error here to the user.
+ Log.e(TAG, "Did not have a sample string for the requested language");
}
}
}
@@ -302,14 +502,14 @@ public boolean onPreferenceChange(Preference preference, Object objValue) {
Log.i(TAG, "TTS use default settings is "+objValue.toString());
} else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
// Default rate
- int value = Integer.parseInt((String) objValue);
+ mDefaultRate = Integer.parseInt((String) objValue);
try {
Settings.Secure.putInt(getContentResolver(),
- TTS_DEFAULT_RATE, value);
+ TTS_DEFAULT_RATE, mDefaultRate);
if (mTts != null) {
- mTts.setSpeechRate((float)(value/100.0f));
+ mTts.setSpeechRate((float)(mDefaultRate/100.0f));
}
- Log.i(TAG, "TTS default rate is "+value);
+ Log.i(TAG, "TTS default rate is " + mDefaultRate);
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist default TTS rate setting", e);
}
@@ -323,8 +523,22 @@ public boolean onPreferenceChange(Preference preference, Object objValue) {
Log.v(TAG, "TTS default lang/country/variant set to "
+ mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
if (mTts != null) {
- mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry));
+ mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
+ }
+ int newIndex = mDefaultLocPref.findIndexOfValue((String)objValue);
+ Log.v("Settings", " selected is " + newIndex);
+ mDemoStringIndex = newIndex > -1 ? newIndex : 0;
+ } else if (KEY_TTS_DEFAULT_SYNTH.equals(preference.getKey())) {
+ mDefaultEng = objValue.toString();
+ Settings.Secure.putString(getContentResolver(), TTS_DEFAULT_SYNTH, mDefaultEng);
+ if (mTts != null) {
+ mTts.setEngineByPackageName(mDefaultEng);
+ mEnableDemo = false;
+ mVoicesMissing = false;
+ updateWidgetState();
+ checkVoiceData();
}
+ Log.v("Settings", "The default synth is: " + objValue.toString());
}
return true;
@@ -336,11 +550,9 @@ public boolean onPreferenceChange(Preference preference, Object objValue) {
*/
public boolean onPreferenceClick(Preference preference) {
if (preference == mPlayExample) {
- // Play example
- if (mTts != null) {
- mTts.speak(getResources().getString(R.string.tts_demo),
- TextToSpeech.QUEUE_FLUSH, null);
- }
+ // Get the sample text from the TTS engine; onActivityResult will do
+ // the actual speaking
+ getSampleText();
return true;
}
if (preference == mInstallData) {
@@ -352,6 +564,46 @@ public boolean onPreferenceClick(Preference preference) {
return false;
}
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (Utils.isMonkeyRunning()) {
+ return false;
+ }
+
+ if (preference instanceof CheckBoxPreference) {
+ final CheckBoxPreference chkPref = (CheckBoxPreference) preference;
+ if (!chkPref.getKey().equals(KEY_TTS_USE_DEFAULT)){
+ if (chkPref.isChecked()) {
+ chkPref.setChecked(false);
+ AlertDialog d = (new AlertDialog.Builder(this))
+ .setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(getString(R.string.tts_engine_security_warning,
+ chkPref.getTitle()))
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ chkPref.setChecked(true);
+ loadEngines();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ })
+ .create();
+ d.show();
+ } else {
+ loadEngines();
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
private void updateWidgetState() {
mPlayExample.setEnabled(mEnableDemo);
@@ -359,7 +611,7 @@ private void updateWidgetState() {
mDefaultRatePref.setEnabled(mEnableDemo);
mDefaultLocPref.setEnabled(mEnableDemo);
- mInstallData.setEnabled(!mEnableDemo);
+ mInstallData.setEnabled(mVoicesMissing);
}
@@ -380,25 +632,137 @@ private void parseLocaleInfo(String locale) {
}
- private void setDefaultLocalePref(String language, String country, String variant) {
- // build a string from the default lang/country/variant trio,
- String localeString = new String(language);
- if (country.compareTo("") != 0) {
- localeString += LOCALE_DELIMITER + country;
- } else {
- localeString += LOCALE_DELIMITER + " ";
+ /**
+ * Initialize the default language in the UI and in the preferences.
+ * After this method has been invoked, the default language is a supported Locale.
+ */
+ private void initDefaultLang() {
+ // if there isn't already a default language preference
+ if (!hasLangPref()) {
+ // if the current Locale is supported
+ if (isCurrentLocSupported()) {
+ // then use the current Locale as the default language
+ useCurrentLocAsDefault();
+ } else {
+ // otherwise use a default supported Locale as the default language
+ useSupportedLocAsDefault();
+ }
}
- if (variant.compareTo("") != 0) {
- localeString += LOCALE_DELIMITER + variant;
+
+ // Update the language preference list with the default language and the matching
+ // demo string (at this stage there is a default language pref)
+ ContentResolver resolver = getContentResolver();
+ mDefaultLanguage = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
+ mDefaultCountry = Settings.Secure.getString(resolver, TTS_DEFAULT_COUNTRY);
+ mDefaultLocVariant = Settings.Secure.getString(resolver, TTS_DEFAULT_VARIANT);
+
+ // update the demo string
+ mDemoStringIndex = mDefaultLocPref.findIndexOfValue(mDefaultLanguage + LOCALE_DELIMITER
+ + mDefaultCountry);
+ if (mDemoStringIndex > -1){
+ mDefaultLocPref.setValueIndex(mDemoStringIndex);
}
+ }
- if (mDefaultLocPref.findIndexOfValue(localeString) > -1) {
- mDefaultLocPref.setValue(localeString);
- } else {
- mDefaultLocPref.setValueIndex(0);
+ /**
+ * (helper function for initDefaultLang() )
+ * Returns whether there is a default language in the TTS settings.
+ */
+ private boolean hasLangPref() {
+ ContentResolver resolver = getContentResolver();
+ String language = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
+ if ((language == null) || (language.length() < 1)) {
+ return false;
+ }
+ String country = Settings.Secure.getString(resolver, TTS_DEFAULT_COUNTRY);
+ if (country == null) {
+ return false;
+ }
+ String variant = Settings.Secure.getString(resolver, TTS_DEFAULT_VARIANT);
+ if (variant == null) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * (helper function for initDefaultLang() )
+ * Returns whether the current Locale is supported by this Settings screen
+ */
+ private boolean isCurrentLocSupported() {
+ String currentLocID = Locale.getDefault().getISO3Language() + LOCALE_DELIMITER
+ + Locale.getDefault().getISO3Country();
+ return (mDefaultLocPref.findIndexOfValue(currentLocID) > -1);
+ }
+
+ /**
+ * (helper function for initDefaultLang() )
+ * Sets the default language in TTS settings to be the current Locale.
+ * This should only be used after checking that the current Locale is supported.
+ */
+ private void useCurrentLocAsDefault() {
+ Locale currentLocale = Locale.getDefault();
+ ContentResolver resolver = getContentResolver();
+ Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, currentLocale.getISO3Language());
+ Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, currentLocale.getISO3Country());
+ Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, currentLocale.getVariant());
+ }
+
+ /**
+ * (helper function for initDefaultLang() )
+ * Sets the default language in TTS settings to be one known to be supported
+ */
+ private void useSupportedLocAsDefault() {
+ ContentResolver resolver = getContentResolver();
+ Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, DEFAULT_LANG_VAL);
+ Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, DEFAULT_COUNTRY_VAL);
+ Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, DEFAULT_VARIANT_VAL);
+ }
+
+
+ private void loadEngines() {
+ mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
+
+ // TODO (clchen): Try to see if it is possible to be more efficient here
+ // and not search for plugins again.
+ Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
+ ResolveInfo[] enginesArray = new ResolveInfo[0];
+ PackageManager pm = getPackageManager();
+ enginesArray = pm.queryIntentActivities(intent, 0).toArray(enginesArray);
+ ArrayList entries = new ArrayList();
+ ArrayList values = new ArrayList | |