Initial Contribution

This commit is contained in:
The Android Open Source Project
2008-10-21 07:00:00 -07:00
commit de2d9f5f10
215 changed files with 26261 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
/*
* 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.internal.telephony.PhoneStateIntentReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.provider.Settings;
import android.telephony.ServiceState;
public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListener {
private final Context mContext;
private PhoneStateIntentReceiver mPhoneStateReceiver;
private final CheckBoxPreference mCheckBoxPref;
private static final int EVENT_SERVICE_STATE_CHANGED = 3;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SERVICE_STATE_CHANGED:
onAirplaneModeChanged();
break;
}
}
};
public AirplaneModeEnabler(Context context, CheckBoxPreference airplaneModeCheckBoxPreference) {
mContext = context;
mCheckBoxPref = airplaneModeCheckBoxPreference;
airplaneModeCheckBoxPreference.setPersistent(false);
mPhoneStateReceiver = new PhoneStateIntentReceiver(mContext, mHandler);
mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
}
public void resume() {
// This is the widget enabled state, not the preference toggled state
mCheckBoxPref.setEnabled(true);
mCheckBoxPref.setChecked(isAirplaneModeOn());
mPhoneStateReceiver.registerIntent();
mCheckBoxPref.setOnPreferenceChangeListener(this);
}
public void pause() {
mPhoneStateReceiver.unregisterIntent();
mCheckBoxPref.setOnPreferenceChangeListener(null);
}
private boolean isAirplaneModeOn() {
return Settings.System.getInt(mContext.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) != 0;
}
private void setAirplaneModeOn(boolean enabling) {
mCheckBoxPref.setEnabled(false);
mCheckBoxPref.setSummary(enabling ? R.string.airplane_mode_turning_on
: R.string.airplane_mode_turning_off);
// Change the system setting
Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
enabling ? 1 : 0);
// Post the intent
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", enabling);
mContext.sendBroadcast(intent);
}
/**
* Called when we've received confirmation that the airplane mode was set.
*/
private void onAirplaneModeChanged() {
ServiceState serviceState = mPhoneStateReceiver.getServiceState();
boolean isPhoneOff = serviceState.getState() == ServiceState.STATE_POWER_OFF;
mCheckBoxPref.setChecked(isPhoneOff);
mCheckBoxPref.setSummary(R.string.airplane_mode_summary);
mCheckBoxPref.setEnabled(true);
}
/**
* Called when someone clicks on the checkbox preference.
*/
public boolean onPreferenceChange(Preference preference, Object newValue) {
setAirplaneModeOn((Boolean) newValue);
return true;
}
}

View File

@@ -0,0 +1,393 @@
/*
* 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 android.app.AlertDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemProperties;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.provider.Telephony;
import com.android.internal.telephony.TelephonyProperties;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
public class ApnEditor extends PreferenceActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
private final static String TAG = ApnEditor.class.getSimpleName();
private final static String SAVED_POS = "pos";
private static final int MENU_DELETE = Menu.FIRST;
private static final int MENU_SAVE = Menu.FIRST + 1;
private static final int MENU_CANCEL = Menu.FIRST + 2;
private static String sNotSet;
private EditTextPreference mName;
private EditTextPreference mApn;
private EditTextPreference mProxy;
private EditTextPreference mPort;
private EditTextPreference mUser;
private EditTextPreference mServer;
private EditTextPreference mPassword;
private EditTextPreference mMmsc;
private EditTextPreference mMcc;
private EditTextPreference mMnc;
private EditTextPreference mMmsProxy;
private EditTextPreference mMmsPort;
private EditTextPreference mApnType;
private Uri mUri;
private Cursor mCursor;
private boolean mNewApn;
private boolean mFirstTime;
private Resources mRes;
/**
* Standard projection for the interesting columns of a normal note.
*/
private static final String[] sProjection = new String[] {
Telephony.Carriers._ID, // 0
Telephony.Carriers.NAME, // 1
Telephony.Carriers.APN, // 2
Telephony.Carriers.PROXY, // 3
Telephony.Carriers.PORT, // 4
Telephony.Carriers.USER, // 5
Telephony.Carriers.SERVER, // 6
Telephony.Carriers.PASSWORD, // 7
Telephony.Carriers.MMSC, // 8
Telephony.Carriers.MCC, // 9
Telephony.Carriers.MNC, // 10
Telephony.Carriers.NUMERIC, // 11
Telephony.Carriers.MMSPROXY,// 12
Telephony.Carriers.MMSPORT, // 13
Telephony.Carriers.TYPE, // 14
};
private static final int ID_INDEX = 0;
private static final int NAME_INDEX = 1;
private static final int APN_INDEX = 2;
private static final int PROXY_INDEX = 3;
private static final int PORT_INDEX = 4;
private static final int USER_INDEX = 5;
private static final int SERVER_INDEX = 6;
private static final int PASSWORD_INDEX = 7;
private static final int MMSC_INDEX = 8;
private static final int MCC_INDEX = 9;
private static final int MNC_INDEX = 10;
private static final int MMSPROXY_INDEX = 12;
private static final int MMSPORT_INDEX = 13;
private static final int TYPE_INDEX = 14;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.apn_editor);
sNotSet = getResources().getString(R.string.apn_not_set);
mName = (EditTextPreference) findPreference("apn_name");
mApn = (EditTextPreference) findPreference("apn_apn");
mProxy = (EditTextPreference) findPreference("apn_http_proxy");
mPort = (EditTextPreference) findPreference("apn_http_port");
mUser = (EditTextPreference) findPreference("apn_user");
mServer = (EditTextPreference) findPreference("apn_server");
mPassword = (EditTextPreference) findPreference("apn_password");
mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy");
mMmsPort = (EditTextPreference) findPreference("apn_mms_port");
mMmsc = (EditTextPreference) findPreference("apn_mmsc");
mMcc = (EditTextPreference) findPreference("apn_mcc");
mMnc = (EditTextPreference) findPreference("apn_mnc");
mApnType = (EditTextPreference) findPreference("apn_type");
mRes = getResources();
final Intent intent = getIntent();
final String action = intent.getAction();
mFirstTime = icicle == null;
if (action.equals(Intent.ACTION_EDIT)) {
mUri = intent.getData();
} else if (action.equals(Intent.ACTION_INSERT)) {
if (mFirstTime) {
mUri = getContentResolver().insert(intent.getData(), new ContentValues());
} else {
mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI,
icicle.getInt(SAVED_POS));
}
mNewApn = true;
// If we were unable to create a new note, then just finish
// this activity. A RESULT_CANCELED will be sent back to the
// original activity if they requested a result.
if (mUri == null) {
Log.w(TAG, "Failed to insert new telephony provider into "
+ getIntent().getData());
finish();
return;
}
// The new entry was created, so assume all will end well and
// set the result to be returned.
setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
} else {
finish();
return;
}
mCursor = managedQuery(mUri, sProjection, null, null);
mCursor.moveToFirst();
fillUi();
}
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
private void fillUi() {
if (mFirstTime) {
mFirstTime = false;
// Fill in all the values from the db in both text editor and summary
mName.setText(mCursor.getString(NAME_INDEX));
mApn.setText(mCursor.getString(APN_INDEX));
mProxy.setText(mCursor.getString(PROXY_INDEX));
mPort.setText(mCursor.getString(PORT_INDEX));
mUser.setText(mCursor.getString(USER_INDEX));
mServer.setText(mCursor.getString(SERVER_INDEX));
mPassword.setText(mCursor.getString(PASSWORD_INDEX));
mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX));
mMmsPort.setText(mCursor.getString(MMSPORT_INDEX));
mMmsc.setText(mCursor.getString(MMSC_INDEX));
mMcc.setText(mCursor.getString(MCC_INDEX));
mMnc.setText(mCursor.getString(MNC_INDEX));
mApnType.setText(mCursor.getString(TYPE_INDEX));
if (mNewApn) {
String numeric =
SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC);
// MCC is first 3 chars and then in 2 - 3 chars of MNC
if (numeric != null && numeric.length() > 4) {
// Country code
String mcc = numeric.substring(0, 3);
// Network code
String mnc = numeric.substring(3);
// Auto populate MNC and MCC for new entries, based on what SIM reports
mMcc.setText(mcc);
mMnc.setText(mnc);
}
}
}
mName.setSummary(checkNull(mName.getText()));
mApn.setSummary(checkNull(mApn.getText()));
mProxy.setSummary(checkNull(mProxy.getText()));
mPort.setSummary(checkNull(mPort.getText()));
mUser.setSummary(checkNull(mUser.getText()));
mServer.setSummary(checkNull(mServer.getText()));
mPassword.setSummary(starify(mPassword.getText()));
mMmsProxy.setSummary(checkNull(mMmsProxy.getText()));
mMmsPort.setSummary(checkNull(mMmsPort.getText()));
mMmsc.setSummary(checkNull(mMmsc.getText()));
mMcc.setSummary(checkNull(mMcc.getText()));
mMnc.setSummary(checkNull(mMnc.getText()));
mApnType.setSummary(checkNull(mApnType.getText()));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// If it's a new APN, then cancel will delete the new entry in onPause
if (!mNewApn) {
menu.add(0, MENU_DELETE, 0, R.string.menu_delete)
.setIcon(android.R.drawable.ic_menu_delete);
}
menu.add(0, MENU_SAVE, 0, R.string.menu_save)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(0, MENU_CANCEL, 0, R.string.menu_cancel)
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_DELETE:
deleteApn();
return true;
case MENU_SAVE:
if (validateAndSave(false)) {
finish();
}
return true;
case MENU_CANCEL:
if (mNewApn) {
getContentResolver().delete(mUri, null, null);
}
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (validateAndSave(false)) {
finish();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
validateAndSave(true);
icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX));
}
/**
* Check the key fields' validity and save if valid.
* @param force save even if the fields are not valid, if the app is
* being suspended
* @return true if the data was saved
*/
private boolean validateAndSave(boolean force) {
String name = checkNotSet(mName.getText());
String apn = checkNotSet(mApn.getText());
String mcc = checkNotSet(mMcc.getText());
String mnc = checkNotSet(mMnc.getText());
String errorMsg = null;
if (name.length() < 1) {
errorMsg = mRes.getString(R.string.error_name_empty);
} else if (apn.length() < 1) {
errorMsg = mRes.getString(R.string.error_apn_empty);
} else if (mcc.length() != 3) {
errorMsg = mRes.getString(R.string.error_mcc_not3);
} else if ((mnc.length() & 0xFFFE) != 2) {
errorMsg = mRes.getString(R.string.error_mnc_not23);
}
if (errorMsg != null && !force) {
showErrorMessage(errorMsg);
return false;
}
if (!mCursor.moveToFirst()) {
Log.w(TAG,
"Could not go to the first row in the Cursor when saving data.");
return false;
}
ContentValues values = new ContentValues();
values.put(Telephony.Carriers.NAME, name);
values.put(Telephony.Carriers.APN, apn);
values.put(Telephony.Carriers.PROXY, checkNotSet(mProxy.getText()));
values.put(Telephony.Carriers.PORT, checkNotSet(mPort.getText()));
values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText()));
values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText()));
values.put(Telephony.Carriers.USER, checkNotSet(mUser.getText()));
values.put(Telephony.Carriers.SERVER, checkNotSet(mServer.getText()));
values.put(Telephony.Carriers.PASSWORD, checkNotSet(mPassword.getText()));
values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText()));
values.put(Telephony.Carriers.TYPE, checkNotSet(mApnType.getText()));
values.put(Telephony.Carriers.MCC, mcc);
values.put(Telephony.Carriers.MNC, mnc);
values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
getContentResolver().update(mUri, values, null, null);
return true;
}
private void showErrorMessage(String message) {
new AlertDialog.Builder(this)
.setTitle(R.string.error_title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.show();
}
private void deleteApn() {
getContentResolver().delete(mUri, null, null);
finish();
}
private String starify(String value) {
if (value == null || value.length() == 0) {
return sNotSet;
} else {
char[] password = new char[value.length()];
for (int i = 0; i < password.length; i++) {
password[i] = '*';
}
return new String(password);
}
}
private String checkNull(String value) {
if (value == null || value.length() == 0) {
return sNotSet;
} else {
return value;
}
}
private String checkNotSet(String value) {
if (value == null || value.equals(sNotSet)) {
return "";
} else {
return value;
}
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref != null) {
pref.setSummary(checkNull(sharedPreferences.getString(key, "")));
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* 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.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Telephony;
import android.view.Menu;
import android.view.MenuItem;
public class ApnSettings extends PreferenceActivity {
public static final String EXTRA_POSITION = "position";
private static final int ID_INDEX = 0;
private static final int NAME_INDEX = 1;
private static final int APN_INDEX = 2;
private static final int MENU_NEW = Menu.FIRST;
private Cursor mCursor;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.apn_settings);
}
@Override
protected void onResume() {
super.onResume();
fillList();
}
private void fillList() {
mCursor = managedQuery(Telephony.Carriers.CONTENT_URI, new String[] {
"_id", "name", "apn"}, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
PreferenceCategory apnList = (PreferenceCategory) findPreference("apn_list");
apnList.removeAll();
mCursor.moveToFirst();
while (!mCursor.isAfterLast()) {
String name = mCursor.getString(NAME_INDEX);
String apn = mCursor.getString(APN_INDEX);
Preference pref = new Preference((Context) this);
pref.setKey(mCursor.getString(ID_INDEX));
pref.setTitle(name);
pref.setSummary(apn);
pref.setPersistent(false);
apnList.addPreference(pref);
mCursor.moveToNext();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_NEW, 0,
getResources().getString(R.string.menu_new))
.setIcon(android.R.drawable.ic_menu_add);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_NEW:
addNewApn();
return true;
}
return super.onOptionsItemSelected(item);
}
private void addNewApn() {
startActivity(new Intent(Intent.ACTION_INSERT, Telephony.Carriers.CONTENT_URI));
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
int pos = Integer.parseInt(preference.getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
startActivity(new Intent(Intent.ACTION_EDIT, url));
return true;
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.provider.Settings;
public class ApplicationSettings extends PreferenceActivity implements
DialogInterface.OnClickListener {
private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
private CheckBoxPreference mToggleAppInstallation;
private DialogInterface mWarnInstallApps;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.application_settings);
mToggleAppInstallation = (CheckBoxPreference) findPreference(KEY_TOGGLE_INSTALL_APPLICATIONS);
mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mToggleAppInstallation) {
if (mToggleAppInstallation.isChecked()) {
mToggleAppInstallation.setChecked(false);
warnAppInstallation();
} else {
setNonMarketAppsAllowed(false);
}
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
public void onClick(DialogInterface dialog, int which) {
if (dialog == mWarnInstallApps && which == DialogInterface.BUTTON1) {
setNonMarketAppsAllowed(true);
mToggleAppInstallation.setChecked(true);
}
}
private void setNonMarketAppsAllowed(boolean enabled) {
// Change the system setting
Settings.System.putInt(getContentResolver(), Settings.System.INSTALL_NON_MARKET_APPS,
enabled ? 1 : 0);
}
private boolean isNonMarketAppsAllowed() {
return Settings.System.getInt(getContentResolver(),
Settings.System.INSTALL_NON_MARKET_APPS, 0) > 0;
}
private void warnAppInstallation() {
mWarnInstallApps = new AlertDialog.Builder(this)
.setTitle(getString(R.string.error_title))
.setIcon(com.android.internal.R.drawable.ic_dialog_alert)
.setMessage(getResources().getString(R.string.install_all_warning))
.setPositiveButton(android.R.string.yes, this)
.setNegativeButton(android.R.string.no, null)
.show();
}
}

View File

@@ -0,0 +1,217 @@
package com.android.settings;
import android.app.Activity;
import android.app.AlertDialog;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import android.os.Bundle;
import android.os.Message;
import android.os.Handler;
import android.os.AsyncResult;
import android.util.Log;
import android.content.DialogInterface;
import android.view.View;
import android.view.WindowManager;
import android.view.Window;
import android.widget.ListView;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
/**
* Radio Band Mode Selection Class
*
* It will query baseband about all available band modes and display them
* in screen. It will display all six band modes if the query failed.
*
* After user select one band, it will send the selection to baseband.
*
* It will alter user the result of select operation and exit, no matter success
* or not.
*
*/
public class BandMode extends Activity {
private static final String LOG_TAG = "phone";
private static final boolean DBG = false;
private static final int EVENT_BAND_SCAN_COMPLETED = 100;
private static final int EVENT_BAND_SELECTION_DONE = 200;
private static final String[] BAND_NAMES = new String[] {
"Automatic",
"EURO Band",
"USA Band",
"JAPAN Band",
"AUS Band",
"AUS2 Band"
};
private ListView mBandList;
private ArrayAdapter mBandListAdapter;
private BandListItem mTargetBand = null;
private DialogInterface mProgressPanel;
private Phone mPhone = null;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.band_mode);
setTitle(getString(R.string.band_mode_title));
getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
mPhone = PhoneFactory.getDefaultPhone();
mBandList = (ListView) findViewById(R.id.band);
mBandListAdapter = new ArrayAdapter<BandListItem>(this,
android.R.layout.simple_list_item_1);
mBandList.setAdapter(mBandListAdapter);
mBandList.setOnItemClickListener(mBandSelectionHandler);
loadBandList();
}
private AdapterView.OnItemClickListener mBandSelectionHandler =
new AdapterView.OnItemClickListener () {
public void onItemClick(AdapterView parent, View v,
int position, long id) {
getWindow().setFeatureInt(
Window.FEATURE_INDETERMINATE_PROGRESS,
Window.PROGRESS_VISIBILITY_ON);
mTargetBand = (BandListItem) parent.getAdapter().getItem(position);
if (DBG) log("Select band : " + mTargetBand.toString());
Message msg =
mHandler.obtainMessage(EVENT_BAND_SELECTION_DONE);
mPhone.setBandMode(mTargetBand.getBand(), msg);
}
};
private class BandListItem {
private int mBandMode = Phone.BM_UNSPECIFIED;
public BandListItem(int bm) {
mBandMode = bm;
}
public int getBand() {
return mBandMode;
}
public String toString() {
return BAND_NAMES[mBandMode];
}
}
private void loadBandList() {
String str = getString(R.string.band_mode_loading);
if (DBG) log(str);
//ProgressDialog.show(this, null, str, true, true, null);
mProgressPanel = new AlertDialog.Builder(this)
.setMessage(str)
.show();
Message msg = mHandler.obtainMessage(EVENT_BAND_SCAN_COMPLETED);
mPhone.queryAvailableBandMode(msg);
}
private void bandListLoaded(AsyncResult result) {
if (DBG) log("network list loaded");
if (mProgressPanel != null) mProgressPanel.dismiss();
clearList();
boolean addBandSuccess = false;
BandListItem item;
if (result.result != null) {
int bands[] = (int[])result.result;
int size = bands[0];
if (size > 0) {
for (int i=1; i<size; i++) {
item = new BandListItem(bands[i]);
mBandListAdapter.add(item);
if (DBG) log("Add " + item.toString());
}
addBandSuccess = true;
}
}
if (addBandSuccess == false) {
if (DBG) log("Error in query, add default list");
for (int i=0; i<Phone.BM_BOUNDARY; i++) {
item = new BandListItem(i);
mBandListAdapter.add(item);
if (DBG) log("Add default " + item.toString());
}
}
mBandList.requestFocus();
}
private void displayBandSelectionResult(Throwable ex) {
String status = getString(R.string.band_mode_set)
+" [" + mTargetBand.toString() + "] ";
if (ex != null) {
status = status + getString(R.string.band_mode_failed);
} else {
status = status + getString(R.string.band_mode_succeeded);
}
mProgressPanel = new AlertDialog.Builder(this)
.setMessage(status)
.setPositiveButton(android.R.string.ok, null).show();
}
private void clearList() {
while(mBandListAdapter.getCount() > 0) {
mBandListAdapter.remove(
mBandListAdapter.getItem(0));
}
}
private void log(String msg) {
Log.d(LOG_TAG, "[BandsList] " + msg);
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_BAND_SCAN_COMPLETED:
ar = (AsyncResult) msg.obj;
bandListLoaded(ar);
break;
case EVENT_BAND_SELECTION_DONE:
ar = (AsyncResult) msg.obj;
getWindow().setFeatureInt(
Window.FEATURE_INDETERMINATE_PROGRESS,
Window.PROGRESS_VISIBILITY_OFF);
displayBandSelectionResult(ar.exception);
break;
}
}
};
}

View File

@@ -0,0 +1,208 @@
/*
* 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 android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.pim.DateUtils;
import android.widget.TextView;
import com.android.internal.app.IBatteryStats;
public class BatteryInfo extends Activity {
private TextView mStatus;
private TextView mLevel;
private TextView mScale;
private TextView mHealth;
private TextView mVoltage;
private TextView mTemperature;
private TextView mTechnology;
private TextView mUptime;
private TextView mAwakeBattery;
private TextView mAwakePlugged;
private TextView mScreenOn;
private IBatteryStats mBatteryStats;
private IPowerManager mScreenStats;
private static final int EVENT_TICK = 1;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_TICK:
updateBatteryStats();
sendEmptyMessageDelayed(EVENT_TICK, 1000);
break;
}
}
};
/**
* Format a number of tenths-units as a decimal string without using a
* conversion to float. E.g. 347 -> "34.7"
*/
private final String tenthsToFixedString(int x) {
int tens = x / 10;
return new String("" + tens + "." + (x - 10*tens));
}
/**
*Listens for intent broadcasts
*/
private IntentFilter mIntentFilter;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
int plugType = intent.getIntExtra("plugged", 0);
mLevel.setText("" + intent.getIntExtra("level", 0));
mScale.setText("" + intent.getIntExtra("scale", 0));
mVoltage.setText("" + intent.getIntExtra("voltage", 0) + " "
+ getString(R.string.battery_info_voltage_units));
mTemperature.setText("" + tenthsToFixedString(intent.getIntExtra("temperature", 0))
+ getString(R.string.battery_info_temperature_units));
mTechnology.setText("" + intent.getStringExtra("technology"));
int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
String statusString;
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
statusString = getString(R.string.battery_info_status_charging);
if (plugType > 0) {
statusString = statusString + " " + getString(
(plugType == BatteryManager.BATTERY_PLUGGED_AC)
? R.string.battery_info_status_charging_ac
: R.string.battery_info_status_charging_usb);
}
} else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
statusString = getString(R.string.battery_info_status_discharging);
} else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
statusString = getString(R.string.battery_info_status_not_charging);
} else if (status == BatteryManager.BATTERY_STATUS_FULL) {
statusString = getString(R.string.battery_info_status_full);
} else {
statusString = getString(R.string.battery_info_status_unknown);
}
mStatus.setText(statusString);
int health = intent.getIntExtra("health", BatteryManager.BATTERY_HEALTH_UNKNOWN);
String healthString;
if (health == BatteryManager.BATTERY_HEALTH_GOOD) {
healthString = getString(R.string.battery_info_health_good);
} else if (health == BatteryManager.BATTERY_HEALTH_OVERHEAT) {
healthString = getString(R.string.battery_info_health_overheat);
} else if (health == BatteryManager.BATTERY_HEALTH_DEAD) {
healthString = getString(R.string.battery_info_health_dead);
} else if (health == BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE) {
healthString = getString(R.string.battery_info_health_over_voltage);
} else if (health == BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE) {
healthString = getString(R.string.battery_info_health_unspecified_failure);
} else {
healthString = getString(R.string.battery_info_health_unknown);
}
mHealth.setText(healthString);
}
}
};
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.battery_info);
// create the IntentFilter that will be used to listen
// to battery status broadcasts
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
}
@Override
public void onResume() {
super.onResume();
mStatus = (TextView)findViewById(R.id.status);
mLevel = (TextView)findViewById(R.id.level);
mScale = (TextView)findViewById(R.id.scale);
mHealth = (TextView)findViewById(R.id.health);
mTechnology = (TextView)findViewById(R.id.technology);
mVoltage = (TextView)findViewById(R.id.voltage);
mTemperature = (TextView)findViewById(R.id.temperature);
mUptime = (TextView) findViewById(R.id.uptime);
mAwakeBattery = (TextView) findViewById(R.id.awakeBattery);
mAwakePlugged = (TextView) findViewById(R.id.awakePlugged);
mScreenOn = (TextView) findViewById(R.id.screenOn);
// Get awake time plugged in and on battery
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
mScreenStats = IPowerManager.Stub.asInterface(ServiceManager.getService(POWER_SERVICE));
mHandler.sendEmptyMessageDelayed(EVENT_TICK, 1000);
registerReceiver(mIntentReceiver, mIntentFilter);
}
@Override
public void onPause() {
super.onPause();
mHandler.removeMessages(EVENT_TICK);
// we are no longer on the screen stop the observers
unregisterReceiver(mIntentReceiver);
}
private void updateBatteryStats() {
long uptime = SystemClock.elapsedRealtime();
mUptime.setText(DateUtils.formatElapsedTime(uptime / 1000));
if (mBatteryStats != null) {
try {
long awakeTimeBattery = mBatteryStats.getAwakeTimeBattery();
long awakeTimePluggedIn = mBatteryStats.getAwakeTimePlugged();
mAwakeBattery.setText(DateUtils.formatElapsedTime(awakeTimeBattery / 1000)
+ " (" + (100 * awakeTimeBattery / uptime) + "%)");
mAwakePlugged.setText(DateUtils.formatElapsedTime(awakeTimePluggedIn / 1000)
+ " (" + (100 * awakeTimePluggedIn / uptime) + "%)");
} catch (RemoteException re) {
mAwakeBattery.setText("Unknown");
mAwakePlugged.setText("Unknown");
}
}
if (mScreenStats != null) {
try {
long screenOnTime = mScreenStats.getScreenOnTime();
mScreenOn.setText(DateUtils.formatElapsedTime(screenOnTime / 1000));
} catch (RemoteException re) {
mScreenOn.setText("Unknown");
}
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class BluetoothDataEntry extends Activity implements OnKeyListener {
private Bundle extras;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.bluetooth_data_entry);
mDataLabel = (TextView)findViewById(R.id.dataLabel);
mDataEntry = (EditText)findViewById(R.id.dataEntry);
mConfirmButton = (Button)findViewById(R.id.confirmButton);
mCancelButton = (Button)findViewById(R.id.cancelButton);
mDataEntry.setOnKeyListener(this);
Intent intent = getIntent();
String label = null;
{
String labelExtra = intent.getStringExtra("label");
if (labelExtra != null) {
label = labelExtra;
}
}
extras = intent.getBundleExtra("extras");
if (label != null && label.length() > 0) {
mDataLabel.setText(label);
}
mConfirmButton.setOnClickListener(new ConfirmButtonListener());
mCancelButton.setOnClickListener(new CancelButtonListener());
}
private class ConfirmButtonListener implements OnClickListener {
public void onClick(View v) {
activityResult(RESULT_OK, mDataEntry.getText().toString(), extras);
}
}
private class CancelButtonListener implements OnClickListener {
public void onClick(View v) {
activityResult(RESULT_CANCELED, null, null);
}
}
protected void activityResult(int result, String data, Bundle extras) {
setResult(result, (new Intent()).setAction(data).putExtras(extras));
finish();
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_ENTER) {
activityResult(RESULT_OK, mDataEntry.getText().toString(), extras);
return true;
}
return false;
}
protected TextView mDataLabel;
protected EditText mDataEntry;
protected Button mConfirmButton;
protected Button mCancelButton;
}

View File

@@ -0,0 +1,72 @@
package com.android.settings;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.util.Map;
/**
* This class extends Preference to display bluetooth status icons. One
* icon specifies the connection/pairing status that is right-aligned.
* An optional headset icon can be added to its left as well.
*/
public class BluetoothListItem extends Preference {
private boolean mIsHeadset;
private int mWeight;
public BluetoothListItem(Context context, AttributeSet attrs) {
super(context, attrs);
setWidgetLayoutResource(R.layout.preference_widget_btdevice_status);
}
private void updateIcons(View view) {
ImageView headsetView = (ImageView) view.findViewById(R.id.device_headset);
headsetView.setVisibility(mIsHeadset ? View.VISIBLE : View.GONE);
}
@Override
public void onBindView(View view) {
super.onBindView(view);
updateIcons(view);
}
/**
* Set whether the device is of headset type
* @param headset whether or not the headset icon should be shown
*/
public void setHeadset(boolean headset) {
mIsHeadset = headset;
notifyChanged();
}
/**
* Sets the weight for ordering by signal strength or importance
* @param weight the ordering weight
*/
public void setWeight(int weight) {
mWeight = weight;
}
/**
* Returns the currently set ordering weight
* @return the current ordering weight
*/
public int getWeight() {
return mWeight;
}
@Override
public int compareTo(Preference another) {
int diff = ((BluetoothListItem)another).mWeight - mWeight;
// Let the new one be after the old one, if they are the same weight
// TODO: Implement a more reliable way to consistently order items of
// the same weight
if (diff == 0) diff = 1;
return diff;
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.NotificationManager;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class BluetoothPINEntry extends BluetoothDataEntry {
private BluetoothDevice mBluetooth;
private String mAddress;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
if (!intent.getAction().equals(BluetoothIntent.PAIRING_REQUEST_ACTION))
{
Log.e(this.getClass().getName(),
"Error: this activity may be started only with intent " +
BluetoothIntent.PAIRING_REQUEST_ACTION);
finish();
}
// Cancel the notification, if any
NotificationManager manager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(0xb100ceee);
mAddress = intent.getStringExtra(BluetoothIntent.ADDRESS);
mBluetooth = (BluetoothDevice)getSystemService(BLUETOOTH_SERVICE);
String remoteName = mBluetooth.getRemoteName(mAddress);
if (remoteName == null) {
remoteName = mAddress;
}
mDataLabel.setText(getString(R.string.bluetooth_enter_pin_msg) + remoteName);
}
@Override
public void activityResult(int result, String data, Bundle extras) {
switch (result) {
case RESULT_OK:
byte[] pin = BluetoothDevice.convertPinToBytes(mDataEntry.getText().toString());
if (pin == null) {
return;
}
mBluetooth.setPin(mAddress, pin);
break;
case RESULT_CANCELED:
mBluetooth.cancelPin(mAddress);
break;
}
finish();
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
/**
* This class handles the Bluetooth pairing PIN request from the bluetooth service
* It checks if the BluetoothSettings activity is currently visible and lets that
* activity handle the request. Otherwise it puts a Notification in the status bar,
* which can be clicked to bring up the PIN entry dialog.
*/
public class BluetoothPinRequest extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothIntent.PAIRING_REQUEST_ACTION)) {
if (BluetoothSettings.isRunning()) {
// Let the BluetoothSettings activity handle it
return;
} else {
Resources res = context.getResources();
String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
Notification pair = new Notification(
android.R.drawable.stat_sys_data_bluetooth,
res.getString(R.string.bluetooth_notif_ticker),
System.currentTimeMillis());
Intent pinIntent = new Intent();
pinIntent.setClass(context, BluetoothPINEntry.class);
pinIntent.putExtra(BluetoothIntent.ADDRESS, address);
pinIntent.setAction(BluetoothIntent.PAIRING_REQUEST_ACTION);
PendingIntent pending = PendingIntent.getActivity(context, 0,
pinIntent, PendingIntent.FLAG_ONE_SHOT);
String name = intent.getStringExtra(BluetoothIntent.NAME);
if (name == null) {
BluetoothDevice bluetooth =
(BluetoothDevice)context.getSystemService(Context.BLUETOOTH_SERVICE);
name = bluetooth.getRemoteName(address);
if (name == null) {
name = address;
}
}
pair.setLatestEventInfo(context,
res.getString(R.string.bluetooth_notif_title),
res.getString(R.string.bluetooth_notif_message) + name,
pending);
NotificationManager manager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0xb100ceee, pair);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
/*
* 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.content.Context;
import android.os.RemoteException;
import android.os.IHardwareService;
import android.os.ServiceManager;
import android.preference.SeekBarPreference;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import java.util.Map;
public class BrightnessPreference extends SeekBarPreference implements
SeekBar.OnSeekBarChangeListener {
private SeekBar mSeekBar;
private int mOldBrightness;
// Backlight range is from 0 - 255. Need to make sure that user
// doesn't set the backlight to 0 and get stuck
private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;
private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
public BrightnessPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
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(),
Settings.System.SCREEN_BRIGHTNESS);
} catch (SettingNotFoundException snfe) {
mOldBrightness = MAXIMUM_BACKLIGHT;
}
mSeekBar.setProgress(mOldBrightness - MINIMUM_BACKLIGHT);
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromTouch) {
setBrightness(progress + MINIMUM_BACKLIGHT);
}
public void onStartTrackingTouch(SeekBar seekBar) {
// NA
}
public void onStopTrackingTouch(SeekBar seekBar) {
// NA
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
Settings.System.putInt(getContext().getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS,
mSeekBar.getProgress() + MINIMUM_BACKLIGHT);
} else {
setBrightness(mOldBrightness);
}
}
private void setBrightness(int brightness) {
try {
IHardwareService hardware = IHardwareService.Stub.asInterface(
ServiceManager.getService("hardware"));
if (hardware != null) {
hardware.setScreenBacklight(brightness);
}
} catch (RemoteException doe) {
}
}
}

View File

@@ -0,0 +1,480 @@
/*
* 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.google.android.collect.Lists;
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import static com.android.internal.widget.LockPatternView.DisplayMode;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* If the user has a lock pattern set already, makes them confirm the existing one.
*
* Then, prompts the user to choose a lock pattern:
* - prompts for initial pattern
* - asks for confirmation / restart
* - saves chosen password when confirmed
*/
public class ChooseLockPattern extends Activity implements View.OnClickListener{
// how long after a confirmation message is shown before moving on
static final int INFORMATION_MSG_TIMEOUT_MS = 3000;
// how long we wait to clear a wrong pattern
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
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<LockPatternView.Cell> mChosenPattern = null;
protected LockPatternUtils mLockPatternUtils;
/**
* The patten used during the help screen to show how to draw a pattern.
*/
private final List<LockPatternView.Cell> 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)
));
/**
* The pattern listener that responds according to a user choosing a new
* lock pattern.
*/
protected LockPatternView.OnPatternListener mChooseNewLockPatternListener = new LockPatternView.OnPatternListener() {
public void onPatternStart() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
patternInProgress();
}
public void onPatternCleared() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
}
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
if (mChosenPattern == null) throw new IllegalStateException("null chosen pattern in stage 'need to confirm");
if (mChosenPattern.equals(pattern)) {
updateStage(Stage.ChoiceConfirmed);
} else {
updateStage(Stage.ConfirmWrong);
}
} else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
updateStage(Stage.ChoiceTooShort);
} else {
mChosenPattern = new ArrayList<LockPatternView.Cell>(pattern);
updateStage(Stage.FirstChoiceValid);
}
} else {
throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
+ "entering the pattern.");
}
}
private void patternInProgress() {
mHeaderText.setText(R.string.lockpattern_recording_inprogress);
mFooterText.setText("");
mFooterLeftButton.setEnabled(false);
mFooterRightButton.setEnabled(false);
}
};
/**
* The states of the left footer button.
*/
enum LeftButtonMode {
Cancel(R.string.cancel, true),
CancelDisabled(R.string.cancel, false),
Retry(R.string.lockpattern_retry_button_text, true),
RetryDisabled(R.string.lockpattern_retry_button_text, false),
Gone(ID_EMPTY_MESSAGE, false);
/**
* @param text The displayed text for this mode.
* @param enabled Whether the button should be enabled.
*/
LeftButtonMode(int text, boolean enabled) {
this.text = text;
this.enabled = enabled;
}
final int text;
final boolean enabled;
}
/**
* The states of the right button.
*/
enum RightButtonMode {
Continue(R.string.lockpattern_continue_button_text, true),
ContinueDisabled(R.string.lockpattern_continue_button_text, false),
Confirm(R.string.lockpattern_confirm_button_text, true),
ConfirmDisabled(R.string.lockpattern_confirm_button_text, false),
Ok(android.R.string.ok, true);
/**
* @param text The displayed text for this mode.
* @param enabled Whether the button should be enabled.
*/
RightButtonMode(int text, boolean enabled) {
this.text = text;
this.enabled = enabled;
}
final int text;
final boolean enabled;
}
/**
* Keep track internally of where the user is in choosing a pattern.
*/
protected enum Stage {
Introduction(
R.string.lockpattern_recording_intro_header,
LeftButtonMode.Cancel, RightButtonMode.ContinueDisabled,
R.string.lockpattern_recording_intro_footer, true),
HelpScreen(
R.string.lockpattern_settings_help_how_to_record,
LeftButtonMode.Gone, RightButtonMode.Ok, ID_EMPTY_MESSAGE, false),
ChoiceTooShort(
R.string.lockpattern_recording_incorrect_too_short,
LeftButtonMode.Retry, RightButtonMode.ContinueDisabled,
ID_EMPTY_MESSAGE, true),
FirstChoiceValid(
R.string.lockpattern_pattern_entered_header,
LeftButtonMode.Retry, RightButtonMode.Continue, ID_EMPTY_MESSAGE, false),
NeedToConfirm(
R.string.lockpattern_need_to_confirm,
LeftButtonMode.CancelDisabled, RightButtonMode.ConfirmDisabled,
ID_EMPTY_MESSAGE, true),
ConfirmWrong(
R.string.lockpattern_need_to_unlock_wrong,
LeftButtonMode.Cancel, RightButtonMode.ConfirmDisabled,
ID_EMPTY_MESSAGE, true),
ChoiceConfirmed(
R.string.lockpattern_pattern_confirmed_header,
LeftButtonMode.Cancel, RightButtonMode.Confirm, ID_EMPTY_MESSAGE, false);
/**
* @param headerMessage The message displayed at the top.
* @param leftMode The mode of the left button.
* @param rightMode The mode of the right button.
* @param footerMessage The footer message.
* @param patternEnabled Whether the pattern widget is enabled.
*/
Stage(int headerMessage,
LeftButtonMode leftMode,
RightButtonMode rightMode,
int footerMessage, boolean patternEnabled) {
this.headerMessage = headerMessage;
this.leftMode = leftMode;
this.rightMode = rightMode;
this.footerMessage = footerMessage;
this.patternEnabled = patternEnabled;
}
final int headerMessage;
final LeftButtonMode leftMode;
final RightButtonMode rightMode;
final int footerMessage;
final boolean patternEnabled;
}
private Stage mUiStage = Stage.Introduction;
private Runnable mClearPatternRunnable = new Runnable() {
public void run() {
mLockPatternView.clearPattern();
}
};
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());
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
= (LinearLayoutWithDefaultTouchRecepient) findViewById(
R.id.topLayout);
topLayout.setDefaultTouchRecepient(mLockPatternView);
if (savedInstanceState == null) {
// first launch
updateStage(Stage.Introduction);
if (mLockPatternUtils.savedPatternExists()) {
confirmPattern();
}
} else {
// restore from previous state
final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);
if (patternString != null) {
mChosenPattern = LockPatternUtils.stringToPattern(patternString);
}
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);
mFooterText = (TextView) findViewById(R.id.footerText);
mFooterLeftButton = (TextView) findViewById(R.id.footerLeftButton);
mFooterRightButton = (TextView) findViewById(R.id.footerRightButton);
mFooterLeftButton.setOnClickListener(this);
mFooterRightButton.setOnClickListener(this);
}
public void onClick(View v) {
if (v == mFooterLeftButton) {
if (mUiStage.leftMode == LeftButtonMode.Retry) {
mChosenPattern = null;
mLockPatternView.clearPattern();
updateStage(Stage.Introduction);
} else if (mUiStage.leftMode == LeftButtonMode.Cancel) {
finish();
} else {
throw new IllegalStateException("left footer button pressed, but stage of " +
mUiStage + " doesn't make sense");
}
} else if (v == mFooterRightButton) {
if (mUiStage.rightMode == RightButtonMode.Continue) {
if (mUiStage != Stage.FirstChoiceValid) {
throw new IllegalStateException("expected ui stage " + Stage.FirstChoiceValid
+ " when button is " + RightButtonMode.Continue);
}
updateStage(Stage.NeedToConfirm);
} else if (mUiStage.rightMode == RightButtonMode.Confirm) {
if (mUiStage != Stage.ChoiceConfirmed) {
throw new IllegalStateException("expected ui stage " + Stage.ChoiceConfirmed
+ " when button is " + RightButtonMode.Confirm);
}
saveChosenPatternAndFinish();
} else if (mUiStage.rightMode == RightButtonMode.Ok) {
if (mUiStage != Stage.HelpScreen) {
throw new IllegalStateException("Help screen is only mode with ok button, but " +
"stage is " + mUiStage);
}
mLockPatternView.clearPattern();
mLockPatternView.setDisplayMode(DisplayMode.Correct);
updateStage(Stage.Introduction);
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
if (mUiStage == Stage.HelpScreen) {
updateStage(Stage.Introduction);
return true;
}
}
if (keyCode == KeyEvent.KEYCODE_MENU && mUiStage == Stage.Introduction) {
updateStage(Stage.HelpScreen);
return true;
}
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) {
finish();
}
updateStage(Stage.Introduction);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
if (mChosenPattern != null) {
outState.putString(KEY_PATTERN_CHOICE, LockPatternUtils.patternToString(mChosenPattern));
}
}
/**
* Updates the messages and buttons appropriate to what stage the user
* is at in choosing a view. This doesn't handle clearing out the pattern;
* the pattern is expected to be in the right state.
* @param stage
*/
protected void updateStage(Stage stage) {
mUiStage = stage;
// header text, footer text, visibility and
// enabled state all known from the stage
if (stage == Stage.ChoiceTooShort) {
mHeaderText.setText(
getResources().getString(
stage.headerMessage,
LockPatternUtils.MIN_LOCK_PATTERN_SIZE));
} else {
mHeaderText.setText(stage.headerMessage);
}
if (stage.footerMessage == ID_EMPTY_MESSAGE) {
mFooterText.setText("");
} else {
mFooterText.setText(stage.footerMessage);
}
if (stage.leftMode == LeftButtonMode.Gone) {
mFooterLeftButton.setVisibility(View.GONE);
} else {
mFooterLeftButton.setVisibility(View.VISIBLE);
mFooterLeftButton.setText(stage.leftMode.text);
mFooterLeftButton.setEnabled(stage.leftMode.enabled);
}
mFooterRightButton.setText(stage.rightMode.text);
mFooterRightButton.setEnabled(stage.rightMode.enabled);
// same for whether the patten is enabled
if (stage.patternEnabled) {
mLockPatternView.enableInput();
} else {
mLockPatternView.disableInput();
}
// the rest of the stuff varies enough that it is easier just to handle
// on a case by case basis.
mLockPatternView.setDisplayMode(DisplayMode.Correct);
switch (mUiStage) {
case Introduction:
mLockPatternView.clearPattern();
break;
case HelpScreen:
mLockPatternView.setPattern(DisplayMode.Animate, mAnimatePattern);
break;
case ChoiceTooShort:
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
postClearPatternRunnable();
break;
case FirstChoiceValid:
break;
case NeedToConfirm:
mLockPatternView.clearPattern();
break;
case ConfirmWrong:
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
postClearPatternRunnable();
break;
case ChoiceConfirmed:
break;
}
}
// clear the wrong pattern unless they have started a new one
// already
private void postClearPatternRunnable() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
}
private void saveChosenPatternAndFinish() {
boolean patternExistedBefore = mLockPatternUtils.savedPatternExists();
mLockPatternUtils.saveLockPattern(mChosenPattern);
// if setting pattern for first time, enable the lock gesture. otherwise,
// keep the user's setting.
if (!patternExistedBefore) {
mLockPatternUtils.setLockPatternEnabled(true);
mLockPatternUtils.setVisiblePatternEnabled(true);
}
finish();
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
public class ChooseLockPatternExample extends Activity implements View.OnClickListener {
private static final long START_DELAY = 1000;
protected static final String TAG = "Settings";
private View mNextButton;
private View mSkipButton;
private View mImageView;
private AnimationDrawable mAnimation;
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
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) {
finish();
} else if (v == mNextButton) {
stopAnimation(mAnimation);
Intent intent = new Intent(this, ChooseLockPattern.class);
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();
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.content.Intent;
import android.os.Bundle;
import android.view.View;
public class ChooseLockPatternTutorial extends Activity implements View.OnClickListener {
protected View mNextButton;
protected 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());
if (savedInstanceState == null && lockPatternUtils.savedPatternExists()) {
Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.ChooseLockPattern");
startActivity(intent);
finish();
} else {
initViews();
}
}
private void initViews() {
setContentView(R.layout.choose_lock_pattern_tutorial);
mNextButton = findViewById(R.id.next_button);
mNextButton.setOnClickListener(this);
mSkipButton = findViewById(R.id.skip_button);
mSkipButton.setOnClickListener(this);
}
public void onClick(View v) {
if (v == mSkipButton) {
finish();
} else if (v == mNextButton) {
startActivity(new Intent(this, ChooseLockPatternExample.class));
finish();
}
}
}

View File

@@ -0,0 +1,260 @@
/*
* 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 com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
import android.app.Activity;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.os.Bundle;
import android.widget.TextView;
import android.view.Window;
import java.util.List;
/**
* Launch this when you want the user to confirm their lock pattern.
*
* Sets an activity result of {@link Activity#RESULT_OK} when the user
* successfully confirmed their pattern.
*/
public class ConfirmLockPattern extends Activity {
/**
* Names of {@link CharSequence} fields within the originating {@link Intent}
* that are used to configure the keyguard confirmation view's labeling.
* The view will use the system-defined resource strings for any labels that
* the caller does not supply.
*/
public static final String HEADER_TEXT = "com.android.settings.ConfirmLockPattern.header";
public static final String FOOTER_TEXT = "com.android.settings.ConfirmLockPattern.footer";
public static final String HEADER_WRONG_TEXT = "com.android.settings.ConfirmLockPattern.header_wrong";
public static final String FOOTER_WRONG_TEXT = "com.android.settings.ConfirmLockPattern.footer_wrong";
// how long we wait to clear a wrong pattern
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
private static final String KEY_NUM_WRONG_ATTEMPTS = "num_wrong_attempts";
private LockPatternView mLockPatternView;
private LockPatternUtils mLockPatternUtils;
private int mNumWrongConfirmAttempts;
private CountDownTimer mCountdownTimer;
private TextView mHeaderTextView;
private TextView mFooterTextView;
// caller-supplied text for various prompts
private CharSequence mHeaderText;
private CharSequence mFooterText;
private CharSequence mHeaderWrongText;
private CharSequence mFooterWrongText;
private enum Stage {
NeedToUnlock,
NeedToUnlockWrong,
LockedOut
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLockPatternUtils = new LockPatternUtils(getContentResolver());
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.confirm_lock_pattern);
mHeaderTextView = (TextView) findViewById(R.id.headerText);
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
mFooterTextView = (TextView) findViewById(R.id.footerText);
// make it so unhandled touch events within the unlock screen go to the
// lock pattern view.
final LinearLayoutWithDefaultTouchRecepient topLayout
= (LinearLayoutWithDefaultTouchRecepient) findViewById(
R.id.topLayout);
topLayout.setDefaultTouchRecepient(mLockPatternView);
Intent intent = getIntent();
if (intent != null) {
mHeaderText = intent.getCharSequenceExtra(HEADER_TEXT);
mFooterText = intent.getCharSequenceExtra(FOOTER_TEXT);
mHeaderWrongText = intent.getCharSequenceExtra(HEADER_WRONG_TEXT);
mFooterWrongText = intent.getCharSequenceExtra(FOOTER_WRONG_TEXT);
}
mLockPatternView.setOnPatternListener(mConfirmExistingLockPatternListener);
updateStage(Stage.NeedToUnlock);
if (savedInstanceState != null) {
mNumWrongConfirmAttempts = savedInstanceState.getInt(KEY_NUM_WRONG_ATTEMPTS);
} else {
// on first launch, if no lock pattern is set, then finish with
// success (don't want user to get stuck confirming something that
// doesn't exist).
if (!mLockPatternUtils.savedPatternExists()) {
setResult(RESULT_OK);
finish();
}
}
}
@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 (mCountdownTimer != null) {
mCountdownTimer.cancel();
}
}
@Override
protected void onResume() {
super.onResume();
// if the user is currently locked out, enforce it.
long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
if (deadline != 0) {
handleAttemptLockout(deadline);
}
}
private void updateStage(Stage stage) {
switch (stage) {
case NeedToUnlock:
if (mHeaderText != null) {
mHeaderTextView.setText(mHeaderText);
} else {
mHeaderTextView.setText(R.string.lockpattern_need_to_unlock);
}
if (mFooterText != null) {
mFooterTextView.setText(mFooterText);
} else {
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_footer);
}
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
break;
case NeedToUnlockWrong:
if (mHeaderWrongText != null) {
mHeaderTextView.setText(mHeaderWrongText);
} else {
mHeaderTextView.setText(R.string.lockpattern_need_to_unlock_wrong);
}
if (mFooterWrongText != null) {
mFooterTextView.setText(mFooterWrongText);
} else {
mFooterTextView.setText(R.string.lockpattern_need_to_unlock_wrong_footer);
}
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
break;
case LockedOut:
mLockPatternView.clearPattern();
// enabled = false means: disable input, and have the
// appearance of being disabled.
mLockPatternView.setEnabled(false); // appearance of being disabled
break;
}
}
private Runnable mClearPatternRunnable = new Runnable() {
public void run() {
mLockPatternView.clearPattern();
}
};
// clear the wrong pattern unless they have started a new one
// already
private void postClearPatternRunnable() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
mLockPatternView.postDelayed(mClearPatternRunnable, WRONG_PATTERN_CLEAR_TIMEOUT_MS);
}
/**
* The pattern listener that responds according to a user confirming
* an existing lock pattern.
*/
private LockPatternView.OnPatternListener mConfirmExistingLockPatternListener = new LockPatternView.OnPatternListener() {
public void onPatternStart() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
}
public void onPatternCleared() {
mLockPatternView.removeCallbacks(mClearPatternRunnable);
}
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
if (mLockPatternUtils.checkPattern(pattern)) {
setResult(RESULT_OK);
finish();
} else {
if (pattern.size() >= LockPatternUtils.MIN_LOCK_PATTERN_SIZE &&
++mNumWrongConfirmAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
long deadline = SystemClock.elapsedRealtime() + LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS;
mLockPatternUtils.setLockoutAttemptDeadline(deadline);
handleAttemptLockout(deadline);
} else {
updateStage(Stage.NeedToUnlockWrong);
postClearPatternRunnable();
}
}
}
};
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
updateStage(Stage.LockedOut);
long elapsedRealtime = SystemClock.elapsedRealtime();
mCountdownTimer = new CountDownTimer(
elapsedRealtimeDeadline - elapsedRealtime,
LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
@Override
public void onTick(long millisUntilFinished) {
mHeaderTextView.setText(R.string.lockpattern_too_many_failed_confirmation_attempts_header);
final int secondsCountdown = (int) (millisUntilFinished / 1000);
mFooterTextView.setText(getString(
R.string.lockpattern_too_many_failed_confirmation_attempts_footer,
secondsCountdown));
}
@Override
public void onFinish() {
mNumWrongConfirmAttempts = 0;
updateStage(Stage.NeedToUnlock);
}
}.start();
}
}

View File

@@ -0,0 +1,363 @@
/*
* 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.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.os.SystemClock;
import android.pim.DateFormat;
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.provider.Settings.SettingNotFoundException;
import android.widget.DatePicker;
import android.widget.TimePicker;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class DateTimeSettings
extends PreferenceActivity
implements OnSharedPreferenceChangeListener,
TimePickerDialog.OnTimeSetListener , DatePickerDialog.OnDateSetListener {
private static final String HOURS_12 = "12";
private static final String HOURS_24 = "24";
private Calendar mDummyDate;
private static final String KEY_DATE_FORMAT = "date_format";
private static final String KEY_AUTO_TIME = "auto_time";
private static final int DIALOG_DATEPICKER = 0;
private static final int DIALOG_TIMEPICKER = 1;
private CheckBoxPreference mAutoPref;
private Preference mTimePref;
private Preference mTime24Pref;
private Preference mTimeZone;
private Preference mDatePref;
private ListPreference mDateFormat;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.date_time_prefs);
initUI();
}
private void initUI() {
boolean autoEnabled = getAutoState();
mDummyDate = Calendar.getInstance();
mDummyDate.set(mDummyDate.get(Calendar.YEAR), 11, 31, 13, 0, 0);
mAutoPref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME);
mAutoPref.setChecked(autoEnabled);
mTimePref = findPreference("time");
mTime24Pref = findPreference("24 hour");
mTimeZone = findPreference("timezone");
mDatePref = findPreference("date");
mDateFormat = (ListPreference) findPreference(KEY_DATE_FORMAT);
int currentFormatIndex = -1;
String [] dateFormats = getResources().getStringArray(R.array.date_format_values);
String [] formattedDates = new String[dateFormats.length];
String currentFormat = getDateFormat();
// Initialize if DATE_FORMAT is not set in the system settings
// This can happen after a factory reset (or data wipe)
if (currentFormat == null) {
currentFormat = getResources().getString(R.string.default_date_format);
setDateFormat(currentFormat);
}
for (int i = 0; i < formattedDates.length; i++) {
formattedDates[i] = DateFormat.format(dateFormats[i], mDummyDate).toString();
if (currentFormat.equals(dateFormats[i])) currentFormatIndex = i;
}
mDateFormat.setEntries(formattedDates);
mDateFormat.setEntryValues(R.array.date_format_values);
mDateFormat.setValue(currentFormat);
mTimePref.setEnabled(!autoEnabled);
mDatePref.setEnabled(!autoEnabled);
mTimeZone.setEnabled(!autoEnabled);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onResume() {
super.onResume();
((CheckBoxPreference)mTime24Pref).setChecked(is24Hour());
// Register for time ticks and other reasons for time change
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(mIntentReceiver, filter, null, null);
updateTimeAndDateDisplay();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mIntentReceiver);
}
private void updateTimeAndDateDisplay() {
java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(this);
Date now = Calendar.getInstance().getTime();
Date dummyDate = mDummyDate.getTime();
mTimePref.setSummary(DateFormat.getTimeFormat(this).format(now));
mTimeZone.setSummary(getTimeZoneText());
mDatePref.setSummary(shortDateFormat.format(now));
mDateFormat.setSummary(shortDateFormat.format(dummyDate));
}
public void onDateSet(DatePicker view, int year, int month, int day) {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);
c.set(Calendar.DAY_OF_MONTH, day);
long when = c.getTimeInMillis();
if (when / 1000 < Integer.MAX_VALUE) {
SystemClock.setCurrentTimeMillis(when);
}
updateTimeAndDateDisplay();
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, hourOfDay);
c.set(Calendar.MINUTE, minute);
long when = c.getTimeInMillis();
if (when / 1000 < Integer.MAX_VALUE) {
SystemClock.setCurrentTimeMillis(when);
}
updateTimeAndDateDisplay();
timeUpdated();
}
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (key.equals(KEY_DATE_FORMAT)) {
String format = preferences.getString(key,
getResources().getString(R.string.default_date_format));
Settings.System.putString(getContentResolver(),
Settings.System.DATE_FORMAT, format);
updateTimeAndDateDisplay();
} else if (key.equals(KEY_AUTO_TIME)) {
boolean autoEnabled = preferences.getBoolean(key, true);
Settings.System.putInt(getContentResolver(),
Settings.System.AUTO_TIME,
autoEnabled ? 1 : 0);
mTimePref.setEnabled(!autoEnabled);
mDatePref.setEnabled(!autoEnabled);
mTimeZone.setEnabled(!autoEnabled);
}
}
public Dialog onCreateDialog(int id) {
Dialog d;
switch (id) {
case DIALOG_DATEPICKER: {
final Calendar calendar = Calendar.getInstance();
d = new DatePickerDialog(
this,
this,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH));
d.setTitle(getResources().getString(R.string.date_time_changeDate_text));
break;
}
case DIALOG_TIMEPICKER: {
final Calendar calendar = Calendar.getInstance();
d = new TimePickerDialog(
this,
this,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
DateFormat.is24HourFormat(this));
d.setTitle(getResources().getString(R.string.date_time_changeTime_text));
break;
}
default:
d = null;
break;
}
return d;
}
public void onPrepareDialog(int id, Dialog d) {
switch (id) {
case DIALOG_DATEPICKER: {
DatePickerDialog datePicker = (DatePickerDialog)d;
final Calendar calendar = Calendar.getInstance();
datePicker.updateDate(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH));
break;
}
case DIALOG_TIMEPICKER: {
TimePickerDialog timePicker = (TimePickerDialog)d;
final Calendar calendar = Calendar.getInstance();
timePicker.updateTime(
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE));
break;
}
default:
break;
}
}
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mDatePref) {
showDialog(DIALOG_DATEPICKER);
} else if (preference == mTimePref) {
showDialog(DIALOG_TIMEPICKER);
} else if (preference == mTime24Pref) {
set24Hour(((CheckBoxPreference)mTime24Pref).isChecked());
updateTimeAndDateDisplay();
timeUpdated();
} else if (preference == mTimeZone) {
Intent intent = new Intent();
intent.setClass(this, ZoneList.class);
startActivityForResult(intent, 0);
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
updateTimeAndDateDisplay();
}
private void timeUpdated() {
Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED);
sendBroadcast(timeChanged);
}
/* Get & Set values from the system settings */
private boolean is24Hour() {
String setting = Settings.System.getString(getContentResolver(),
Settings.System.TIME_12_24);
return HOURS_24.equals(setting);
}
private void set24Hour(boolean is24Hour) {
Settings.System.putString(getContentResolver(),
Settings.System.TIME_12_24,
is24Hour? HOURS_24 : HOURS_12);
}
private String getDateFormat() {
return Settings.System.getString(getContentResolver(),
Settings.System.DATE_FORMAT);
}
private boolean getAutoState() {
try {
return Settings.System.getInt(getContentResolver(),
Settings.System.AUTO_TIME) > 0;
} catch (SettingNotFoundException snfe) {
return true;
}
}
private void setDateFormat(String format) {
Settings.System.putString(getContentResolver(), Settings.System.DATE_FORMAT, format);
}
/* Helper routines to format timezone */
private String getTimeZoneText() {
TimeZone tz = java.util.Calendar.getInstance().getTimeZone();
boolean daylight = tz.inDaylightTime(new Date());
StringBuilder sb = new StringBuilder();
sb.append(formatOffset(tz.getRawOffset() +
(daylight ? tz.getDSTSavings() : 0))).
append(", ").
append(tz.getDisplayName(daylight, TimeZone.LONG));
return sb.toString();
}
private char[] formatOffset(int off) {
off = off / 1000 / 60;
char[] buf = new char[9];
buf[0] = 'G';
buf[1] = 'M';
buf[2] = 'T';
if (off < 0) {
buf[3] = '-';
off = -off;
} else {
buf[3] = '+';
}
int hours = off / 60;
int minutes = off % 60;
buf[4] = (char) ('0' + hours / 10);
buf[5] = (char) ('0' + hours % 10);
buf[6] = ':';
buf[7] = (char) ('0' + minutes / 10);
buf[8] = (char) ('0' + minutes % 10);
return buf;
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateTimeAndDateDisplay();
}
};
}

View File

@@ -0,0 +1,41 @@
/*
* 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.os.Bundle;
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;
@Override
protected void onCreate(Bundle icicle) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(icicle);
setContentView(R.layout.date_time_settings_setupwizard);
mNextButton = findViewById(R.id.next_button);
mNextButton.setOnClickListener(this);
}
public void onClick(View v) {
setResult(RESULT_OK);
finish();
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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 android.app.Activity;
import android.widget.EditText;
import android.widget.Button;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.text.TextUtils;
import android.text.Spannable;
import android.text.Selection;
import android.net.Uri;
/**
* A simple activity that provides a UI for sending intents
*/
public class DebugIntentSender extends Activity {
private EditText mIntentField;
private EditText mDataField;
private EditText mAccountField;
private EditText mResourceField;
private Button mSendBroadcastButton;
private Button mStartActivityButton;
private View.OnClickListener mClicked = new View.OnClickListener() {
public void onClick(View v) {
if ((v == mSendBroadcastButton) ||
(v == mStartActivityButton)) {
String intentAction = mIntentField.getText().toString();
String intentData = mDataField.getText().toString();
String account = mAccountField.getText().toString();
String resource = mResourceField.getText().toString();
Intent intent = new Intent(intentAction);
if (!TextUtils.isEmpty(intentData)) {
intent.setData(Uri.parse(intentData));
}
intent.putExtra("account", account);
intent.putExtra("resource", resource);
if (v == mSendBroadcastButton) {
sendBroadcast(intent);
} else {
startActivity(intent);
}
setResult(RESULT_OK);
finish();
}
}
};
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.intent_sender);
mIntentField = (EditText) findViewById(R.id.intent);
mIntentField.setText(Intent.ACTION_SYNC);
Selection.selectAll((Spannable) mIntentField.getText());
mDataField = (EditText) findViewById(R.id.data);
mDataField.setBackgroundResource(android.R.drawable.editbox_background);
mAccountField = (EditText) findViewById(R.id.account);
mResourceField = (EditText) findViewById(R.id.resource);
mSendBroadcastButton = (Button) findViewById(R.id.sendbroadcast);
mSendBroadcastButton.setOnClickListener(mClicked);
mStartActivityButton = (Button) findViewById(R.id.startactivity);
mStartActivityButton.setOnClickListener(mClicked);
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.preference.RingtonePreference;
import android.util.AttributeSet;
import android.util.Config;
import android.util.Log;
public class DefaultRingtonePreference extends RingtonePreference {
private static final String TAG = "DefaultRingtonePreference";
public DefaultRingtonePreference(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);
/*
* Similarly, 'Silent' shouldn't be shown here.
*/
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
}
@Override
protected void onSaveRingtone(Uri ringtoneUri) {
RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri);
}
@Override
protected Uri onRestoreRingtone() {
return RingtoneManager.getActualDefaultRingtoneUri(getContext(), getRingtoneType());
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.os.Bundle;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.text.TextUtils;
/*
* Displays preferences for application developers.
*/
public class DevelopmentSettings extends PreferenceActivity {
private static final String ENABLE_ADB = "enable_adb";
private static final String KEEP_SCREEN_ON = "keep_screen_on";
private CheckBoxPreference mEnableAdb;
private CheckBoxPreference mKeepScreenOn;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.development_prefs);
mEnableAdb = (CheckBoxPreference) findPreference(ENABLE_ADB);
mKeepScreenOn = (CheckBoxPreference) findPreference(KEEP_SCREEN_ON);
}
@Override
protected void onResume() {
super.onResume();
mEnableAdb.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.ADB_ENABLED, 0) != 0);
mKeepScreenOn.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 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"))) {
return false;
}
if (preference == mEnableAdb) {
Settings.System.putInt(getContentResolver(), Settings.System.ADB_ENABLED,
mEnableAdb.isChecked() ? 1 : 0);
} else if (preference == mKeepScreenOn) {
Settings.System.putInt(getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN,
mKeepScreenOn.isChecked() ? 1 : 0);
}
return false;
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.util.Config;
import android.util.Log;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DeviceInfoSettings extends PreferenceActivity {
private static final String TAG = "DeviceInfoSettings";
private static final boolean LOGD = false || Config.LOGD;
private static final String KEY_CONTAINER = "container";
private static final String KEY_TEAM = "team";
private static final String KEY_CONTRIBUTORS = "contributors";
private static final String KEY_TERMS = "terms";
private static final String KEY_LICENSE = "license";
private static final String KEY_COPYRIGHT = "copyright";
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.device_info_settings);
setSummary("firmware_version", "ro.build.version.release");
setSummary("baseband_version", "gsm.version.baseband");
setSummary("device_model", "ro.product.model");
setSummary("build_number", "ro.build.description");
findPreference("kernel_version").setSummary(getFormattedKernelVersion());
/*
* Settings is a generic app and should not contain any device-specific
* info.
*/
PreferenceGroup parentPreference = (PreferenceGroup) findPreference(KEY_CONTAINER);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_TERMS,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_LICENSE,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_CONTRIBUTORS,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_COPYRIGHT,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parentPreference, KEY_TEAM,
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
}
private void setSummary(String preference, String property) {
try {
findPreference(preference).setSummary(
SystemProperties.get(property,
getResources().getString(R.string.device_info_default)));
} catch (RuntimeException e) {
}
}
private String getFormattedKernelVersion() {
String procVersionStr;
try {
BufferedReader reader = new BufferedReader(new FileReader("/proc/version"), 256);
try {
procVersionStr = reader.readLine();
} finally {
reader.close();
}
final String PROC_VERSION_REGEX =
"\\w+\\s+" + /* ignore: Linux */
"\\w+\\s+" + /* ignore: version */
"([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */
"\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx@xxxxx.constant) */
"\\([^)]+\\)\\s+" + /* ignore: (gcc ..) */
"([^\\s]+)\\s+" + /* group 3: #26 */
"(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */
"(.+)"; /* group 4: date */
Pattern p = Pattern.compile(PROC_VERSION_REGEX);
Matcher m = p.matcher(procVersionStr);
if (!m.matches()) {
Log.e(TAG, "Regex did not match on /proc/version: " + procVersionStr);
return "Unavailable";
} else if (m.groupCount() < 4) {
Log.e(TAG, "Regex match on /proc/version only returned " + m.groupCount()
+ " groups");
return "Unavailable";
} else {
return (new StringBuilder(m.group(1)).append("\n").append(
m.group(2)).append(" ").append(m.group(3)).append("\n")
.append(m.group(4))).toString();
}
} catch (IOException e) {
Log.e(TAG,
"IO Exception when getting kernel version for Device Info screen",
e);
return "Unavailable";
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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 android.app.Activity;
import android.app.ActivityManagerNative;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
public class Display extends Activity implements View.OnClickListener {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.display);
mFontSize = (Spinner) findViewById(R.id.fontSize);
mFontSize.setOnItemSelectedListener(mFontSizeChanged);
String[] states = new String[3];
Resources r = getResources();
states[0] = r.getString(R.string.small_font);
states[1] = r.getString(R.string.medium_font);
states[2] = r.getString(R.string.large_font);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, states);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);
mFontSize.setAdapter(adapter);
mPreview = (TextView) findViewById(R.id.preview);
mPreview.setText(r.getText(R.string.font_size_preview_text));
Button save = (Button) findViewById(R.id.save);
save.setText(r.getText(R.string.font_size_save));
save.setOnClickListener(this);
mTextSizeTyped = new TypedValue();
TypedArray styledAttributes =
obtainStyledAttributes(android.R.styleable.TextView);
styledAttributes.getValue(android.R.styleable.TextView_textSize,
mTextSizeTyped);
DisplayMetrics metrics = getResources().getDisplayMetrics();
mDisplayMetrics = new DisplayMetrics();
mDisplayMetrics.density = metrics.density;
mDisplayMetrics.heightPixels = metrics.heightPixels;
mDisplayMetrics.scaledDensity = metrics.scaledDensity;
mDisplayMetrics.widthPixels = metrics.widthPixels;
mDisplayMetrics.xdpi = metrics.xdpi;
mDisplayMetrics.ydpi = metrics.ydpi;
styledAttributes.recycle();
}
@Override
public void onResume() {
super.onResume();
try {
mCurConfig.updateFrom(
ActivityManagerNative.getDefault().getConfiguration());
} catch (RemoteException e) {
}
if (mCurConfig.fontScale < 1) {
mFontSize.setSelection(0);
} else if (mCurConfig.fontScale > 1) {
mFontSize.setSelection(2);
} else {
mFontSize.setSelection(1);
}
updateFontScale();
}
private void updateFontScale() {
mDisplayMetrics.scaledDensity = mDisplayMetrics.density *
mCurConfig.fontScale;
float size = mTextSizeTyped.getDimension(mDisplayMetrics);
mPreview.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}
public void onClick(View v) {
try {
ActivityManagerNative.getDefault().updateConfiguration(mCurConfig);
} catch (RemoteException e) {
}
finish();
}
private Spinner.OnItemSelectedListener mFontSizeChanged
= new Spinner.OnItemSelectedListener() {
public void onItemSelected(android.widget.AdapterView av, View v,
int position, long id) {
if (position == 0) {
mCurConfig.fontScale = .75f;
} else if (position == 2) {
mCurConfig.fontScale = 1.25f;
} else {
mCurConfig.fontScale = 1.0f;
}
updateFontScale();
}
public void onNothingSelected(android.widget.AdapterView av) {
}
};
private Spinner mFontSize;
private TextView mPreview;
private TypedValue mTextSizeTyped;
private DisplayMetrics mDisplayMetrics;
private Configuration mCurConfig = new Configuration();
}

View File

@@ -0,0 +1,84 @@
/*
* 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.content.Context;
import android.preference.EditTextPreference;
import android.text.method.DigitsKeyListener;
import android.text.method.PasswordTransformationMethod;
import android.util.AttributeSet;
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);
}
private OnPinEnteredListener mPinListener;
public EditPinPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditPinPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, 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());
editText.setKeyListener(DigitsKeyListener.getInstance());
}
}
public boolean isDialogOpen() {
return mDialogOpen;
}
@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);
}
}

View File

@@ -0,0 +1,414 @@
/**
* 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.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.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.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
*
*/
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;
//wait times used for the async package manager api
private ApplicationInfo mAppInfo;
private Button mUninstallButton;
private Button mActivitiesButton;
private boolean mSysPackage;
private boolean localLOGV=Config.LOGV || true;
private TextView mTotalSize;
private TextView mAppSize;
private TextView mDataSize;
PackageStats mSizeInfo;
private Button mManageSpaceButton;
private PackageManager mPm;
private String mBStr, mKbStr, mMbStr;
//internal constants used in Handler
private static final int CLEAR_USER_DATA = 1;
private static final int OP_SUCCESSFUL = 1;
private static final int OP_FAILED = 2;
private static final int GET_PKG_SIZE = 2;
private static final String ATTR_PACKAGE_STATS="PackageStats";
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;
default:
break;
}
}
};
private boolean isSystemPackage() {
if ((mAppInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
return false;
}
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);
}
}
private String getSizeStr(long size) {
String retStr = "";
if(size < 1024) {
return String.valueOf(size)+mBStr;
}
long kb, mb, rem;
kb = size >> 10;
rem = size - (kb << 10);
if(kb < 1024) {
if(rem > 512) {
kb++;
}
retStr += String.valueOf(kb)+mKbStr;
return retStr;
}
mb = kb >> 10;
if(kb >= 512) {
//round off
mb++;
}
retStr += String.valueOf(mb)+ mMbStr;
return retStr;
}
/** 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);
mSizeInfo = intent.getParcelableExtra(ManageApplications.APP_PKG_SIZE);
long total = -1;
long code = -1;
long data = -1;
if(mSizeInfo != null) {
total = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
code = mSizeInfo.codeSize;
data = mSizeInfo.dataSize+mSizeInfo.cacheSize;
}
String unknownStr = getString(_UNKNOWN_APP);
mBStr = getString(R.string.b_text);
mKbStr = getString(R.string.kb_text);
mMbStr = getString(R.string.mb_text);
String totalSizeStr = unknownStr;
if(total != -1) {
totalSizeStr = getSizeStr(total);
}
String appSizeStr = unknownStr;
if(code != -1) {
appSizeStr = getSizeStr(code);
}
String dataSizeStr = unknownStr;
if(data != -1) {
dataSizeStr = getSizeStr(data);
}
if(localLOGV) Log.i(TAG, "packageName:"+packageName+", total="+total+
"code="+code+", data="+data);
try {
mAppInfo = mPm.getApplicationInfo(packageName, 0);
} catch (NameNotFoundException e) {
Throwable th = e.fillInStackTrace();
Log.e(TAG, "Exception when retrieving package:"+packageName, e);
displayErrorDialog(R.string.app_not_found_dlg_text, true, true);
}
setContentView(R.layout.installed_app_details);
((ImageView)findViewById(R.id.app_icon)).setImageDrawable(mPm.
getApplicationIcon(mAppInfo));
//set application name TODO version
CharSequence appName = mPm.getApplicationLabel(mAppInfo);
if(appName == null) {
appName = getString(_UNKNOWN_APP);
}
((TextView)findViewById(R.id.app_name)).setText(appName);
CharSequence appDesc = mAppInfo.loadDescription(mPm);
if(appDesc != null) {
((TextView)findViewById(R.id.app_description)).setText(appDesc);
}
//TODO download str and download url
//set values on views
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);
mUninstallButton = ((Button)findViewById(R.id.uninstall_button));
//determine if app is a system app
mSysPackage = isSystemPackage();
if(localLOGV) Log.i(TAG, "Is systemPackage "+mSysPackage);
int btnText;
boolean btnClickable = true;
if(mSysPackage) {
//app can clear user data
if((mAppInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
== ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) {
mUninstallButton.setText(R.string.clear_user_data_text);
//disable button if data is 0
if(data == 0) {
mUninstallButton.setEnabled(false);
} else {
//enable button
mUninstallButton.setOnClickListener(this);
}
} else {
//hide button if diableClearUserData is set
mUninstallButton.setVisibility(View.GONE);
}
} else {
mUninstallButton.setText(R.string.uninstall_text);
mUninstallButton.setOnClickListener(this);
}
//clear activities
mActivitiesButton = (Button)findViewById(R.id.clear_activities_button);
List<ComponentName> prefActList = new ArrayList<ComponentName>();
//intent list cannot be null. so pass empty list
List<IntentFilter> intentList = new ArrayList<IntentFilter>();
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);
}
mManageSpaceButton = (Button)findViewById(R.id.manage_space_button);
if(mAppInfo.manageSpaceActivityName != null) {
mManageSpaceButton.setVisibility(View.VISIBLE);
mManageSpaceButton.setOnClickListener(this);
}
//security permissions section
AppSecurityPermissions asp = new AppSecurityPermissions(this);
PackageInfo pkgInfo;
try {
pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
} catch (NameNotFoundException e) {
Log.w(TAG, "Couldnt retrieve permissions for package:"+packageName);
return;
}
asp.setSecurityPermissionsView(pkgInfo);
LinearLayout securityList = (LinearLayout) findViewById(R.id.security_settings_list);
securityList.addView(asp.getPermissionsView());
}
private void displayErrorDialog(int msgId, final boolean finish, final boolean changed) {
//display confirmation dialog
new AlertDialog.Builder(this)
.setTitle(getString(R.string.app_not_found_dlg_title))
.setIcon(R.drawable.ic_dialog_alert)
.setMessage(getString(msgId))
.setNeutralButton(getString(R.string.dlg_ok),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//force to recompute changed value
setIntentAndFinish(finish, changed);
}
}
)
.show();
}
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);
mUninstallButton.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;
Intent intent = new Intent();
PackageStats newPs = msg.getData().getParcelable(ATTR_PACKAGE_STATS);
long newTot = newPs.cacheSize+newPs.codeSize+newPs.dataSize;
long oldTot = mSizeInfo.cacheSize+mSizeInfo.codeSize+mSizeInfo.dataSize;
if(newTot != oldTot) {
mTotalSize.setText(getSizeStr(newTot));
changed = true;
}
if(newPs.codeSize != mSizeInfo.codeSize) {
mAppSize.setText(getSizeStr(newPs.codeSize));
changed = true;
}
if((newPs.dataSize != mSizeInfo.dataSize) || (newPs.cacheSize != mSizeInfo.cacheSize)) {
mDataSize.setText(getSizeStr(newPs.dataSize+newPs.cacheSize));
changed = true;
}
if(changed) {
mUninstallButton.setText(R.string.clear_user_data_text);
mSizeInfo = newPs;
intent.putExtra(ManageApplications.APP_PKG_SIZE, mSizeInfo);
}
intent.putExtra(ManageApplications.APP_CHG, changed);
setResult(ManageApplications.RESULT_OK, intent);
}
/*
* 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);
PkgSizeObserver observer = new PkgSizeObserver();
mPm.getPackageSizeInfo(packageName, observer);
} else {
mUninstallButton.setText(R.string.clear_user_data_text);
mUninstallButton.setEnabled(true);
}
}
/*
* Private method to initiate clearing user data when the user clicks the clear data
* button for a system package
*/
private void initiateClearUserDataForSysPkg() {
mUninstallButton.setEnabled(false);
//invoke uninstall or clear user data based on sysPackage
boolean recomputeSizes = false;
String packageName = mAppInfo.packageName;
Log.i(TAG, "Clearing user data for system package");
ClearUserDataObserver observer = new ClearUserDataObserver();
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean res = am.clearApplicationUserData(packageName, observer);
if(!res) {
//doesnt initiate clear. some error. should not happen but just log error for now
Log.i(TAG, "Couldnt clear application user data for package:"+packageName);
displayErrorDialog(R.string.clear_data_failed, false, false);
} else {
mUninstallButton.setText(R.string.recompute_size);
}
}
/*
* 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 == mUninstallButton) {
if(mSysPackage) {
//display confirmation dialog
new AlertDialog.Builder(this)
.setTitle(getString(R.string.clear_data_dlg_title))
.setIcon(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)
.show();
} else {
//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, false);
}
} 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);
}
}
public void onClick(DialogInterface dialog, int which) {
if(which == AlertDialog.BUTTON1) {
//invoke uninstall or clear user data based on sysPackage
initiateClearUserDataForSysPkg();
} else {
//cancel do nothing just retain existing screen
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.content.ContentResolver;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings.System;
public class LanguageSettings extends PreferenceActivity {
private final String[] mSettingsUiKey = {
"auto_caps",
"auto_replace",
"auto_punctuate",
};
// Note: Order of this array should correspond to the order of the above array
private final String[] mSettingsSystemId = {
System.TEXT_AUTO_CAPS,
System.TEXT_AUTO_REPLACE,
System.TEXT_AUTO_PUNCTUATE,
};
// Note: Order of this array should correspond to the order of the above array
private final int[] mSettingsDefault = {
1,
1,
1,
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.language_settings);
if (getAssets().getLocales().length == 1) {
getPreferenceScreen().
removePreference(findPreference("language_category"));
}
ContentResolver resolver = getContentResolver();
for (int i = 0; i < mSettingsUiKey.length; i++) {
CheckBoxPreference pref = (CheckBoxPreference) findPreference(mSettingsUiKey[i]);
pref.setChecked(System.getInt(resolver, mSettingsSystemId[i],
mSettingsDefault[i]) > 0);
}
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
for (int i = 0; i < mSettingsUiKey.length; i++) {
if (mSettingsUiKey[i].equals(preference.getKey())) {
System.putInt(getContentResolver(), mSettingsSystemId[i],
((CheckBoxPreference)preference).isChecked()? 1 : 0);
return true;
}
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.Locale;
public class LocalePicker extends ListActivity {
private static final String TAG = "LocalePicker";
Loc[] mLocales;
private static class Loc {
String label;
Locale locale;
public Loc(String label, Locale locale) {
this.label = label;
this.locale = locale;
}
@Override
public String toString() {
return this.label;
}
}
int getContentView() {
return R.layout.locale_picker;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(getContentView());
String[] locales = getAssets().getLocales();
final int N = locales.length;
mLocales = new Loc[N];
for (int i = 0; i < N; i++) {
Locale locale = null;
String s = locales[i];
int len = s.length();
if (len == 0) {
locale = new Locale("en", "US");
} else if (len == 2) {
locale = new Locale(s);
} else if (len == 5) {
locale = new Locale(s.substring(0, 2), s.substring(3, 5));
}
String displayName = "";
if (locale != null) {
displayName = locale.getDisplayName();
}
if ("zz_ZZ".equals(s)) {
displayName = "Pseudo...";
}
mLocales[i] = new Loc(displayName, locale);
}
int layoutId = R.layout.locale_picker_item;
int fieldId = R.id.locale;
ArrayAdapter<Loc> adapter = new ArrayAdapter<Loc>(this, layoutId, fieldId, mLocales);
getListView().setAdapter(adapter);
}
@Override
public void onResume() {
super.onResume();
getListView().requestFocus();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
try {
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config = am.getConfiguration();
Loc loc = mLocales[position];
config.locale = loc.locale;
final String language = loc.locale.getLanguage();
final String region = loc.locale.getCountry();
am.updateConfiguration(config);
// Update the System properties
SystemProperties.set("user.language", language);
SystemProperties.set("user.region", region);
// Write to file for persistence across reboots
try {
BufferedWriter bw = new BufferedWriter(new java.io.FileWriter(
System.getenv("ANDROID_DATA") + "/locale"));
bw.write(language + "_" + region);
bw.close();
} catch (java.io.IOException ioe) {
Log.e(TAG,
"Unable to persist locale. Error writing to locale file."
+ ioe);
}
} catch (RemoteException e) {
// Intentionally left blank
}
finish();
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.Locale;
public class LocalePickerInSetupWizard extends LocalePicker {
@Override
int getContentView() {
return R.layout.locale_picker_in_setupwizard;
}
}

View File

@@ -0,0 +1,616 @@
/*
* 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.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Config;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Activity to pick an application that will be used to display installation information and
* options to upgrade/uninstall/delete user data for system applications.
* Initially a compute in progress message is displayed while the application retrieves
* the size information of installed packages which is done asynchronously through a
* handler. Once the computation is done package resource information is retrieved
* and then the information is displayed on the screen. All
* messages are passed through a Handler object.
* Known issue: There could be some ordering issues when installing/uninstalling
* applications when the application list is being scanned.
*/
public class ManageApplications extends Activity implements SimpleAdapter.ViewBinder, OnItemClickListener {
private static final String TAG = "ManageApplications";
//Application prefix information
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_PKG_SIZE= APP_PKG_PREFIX+"size";
public static final String APP_CHG=APP_PKG_PREFIX+"changed";
//constant value that can be used to check return code from sub activity.
private static final int INSTALLED_APP_DETAILS = 1;
//application attributes passed to sub activity that displays more app info
private static final String KEY_APP_NAME = "ApplicationName";
private static final String KEY_APP_ICON = "ApplicationIcon";
private static final String KEY_APP_DESC = "ApplicationDescription";
private static final String KEY_APP_SIZE= "ApplicationSize";
//sort order that can be changed through the menu
public static final int SORT_ORDER_ALPHA = 0;
public static final int SORT_ORDER_SIZE = 1;
//key and resource values used in constructing map for SimpleAdapter
private static final String sKeys[] = new String[] { KEY_APP_NAME, KEY_APP_ICON,
KEY_APP_DESC, KEY_APP_SIZE};
private static final int sResourceIds[] = new int[] { R.id.app_name, R.id.app_icon,
R.id.app_description, R.id.app_size};
//List of ApplicationInfo objects for various applications
private List<ApplicationInfo> mAppList;
//SimpleAdapter used for managing items in the list
private SimpleAdapter mAppAdapter;
//map used to store size information which is used for displaying size information
//in this activity as well as the subactivity. this is to avoid invoking package manager
//api to retrieve size information
private HashMap<String, PackageStats> mSizeMap;
private HashMap<String, Map<String, ?> > mAppAdapterMap;
//sort order
private int mSortOrder = SORT_ORDER_ALPHA;
//log information boolean
private boolean localLOGV = Config.LOGV || false;
private ApplicationInfo mCurrentPkg;
private int mCurrentPkgIdx = 0;
private static final int COMPUTE_PKG_SIZE_START = 1;
private static final int COMPUTE_PKG_SIZE_DONE = 2;
private static final int REMOVE_PKG=3;
private static final int REORDER_LIST=4;
private static final int ADD_PKG=5;
private static final String ATTR_APP_IDX="ApplicationIndex";
private static final String ATTR_CHAINED="Chained";
private static final String ATTR_PKG_NAME="PackageName";
private PkgSizeObserver mObserver;
private PackageManager mPm;
private PackageIntentReceiver mReceiver;
private boolean mDoneIniting = false;
private String mKbStr;
private String mMbStr;
private String mBStr;
/*
* Handler class to handle messages for various operations
*/
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
PackageStats ps;
ApplicationInfo info;
Bundle data;
String pkgName;
int idx;
int size;
boolean chained = false;
data = msg.getData();
switch (msg.what) {
case COMPUTE_PKG_SIZE_START:
mDoneIniting = false;
//initialize lists
mAppList = new ArrayList<ApplicationInfo>();
mSizeMap = new HashMap<String, PackageStats>();
mAppAdapterMap = new HashMap<String, Map<String, ?> >();
//update application list from PackageManager
mAppList = mPm.getInstalledApplications(0);
if(mAppList.size() == 0) {
return;
}
mCurrentPkgIdx = 0;
mCurrentPkg = mAppList.get(0);
if(localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
//register receiver
mReceiver = new PackageIntentReceiver();
mReceiver.registerReceiver();
pkgName = mCurrentPkg.packageName;
mObserver = new PkgSizeObserver(0);
mObserver.invokeGetSizeInfo(pkgName, true);
break;
case COMPUTE_PKG_SIZE_DONE:
ps = mObserver.ps;
info = mObserver.appInfo;
chained = data.getBoolean(ATTR_CHAINED);
if(!mObserver.succeeded) {
if(chained) {
removePackageFromAppList(ps.packageName);
} else {
//do not go to adding phase
break;
}
} else {
//insert size value
mSizeMap.put(ps.packageName, ps);
Map<String, Object> entry = createMapEntry(mPm.getApplicationLabel(info),
mPm.getApplicationIcon(info),
info.loadDescription(mPm),
getSizeStr(ps));
mAppAdapterMap.put(ps.packageName, entry);
}
if(chained) {
//here app list is precomputed
idx = data.getInt(ATTR_APP_IDX);
//increment only if succeded
if(mObserver.succeeded) {
idx++;
}
if(idx < mAppList.size()) {
pkgName = mAppList.get(idx).packageName;
//increment record index and invoke getSizeInfo for next record
mObserver.invokeGetSizeInfo(pkgName, true);
} else {
sortAppList();
createListFromValues();
mDoneIniting = true;
}
} else {
//add app info object as well
mAppList.add(info);
sortAppList();
size = mAppList.size();
int i;
for(i = 0; i < size; i++) {
if(mAppList.get(i).packageName.equalsIgnoreCase(mCurrentPkg.packageName)) {
if(i > mCurrentPkgIdx) {
mCurrentPkgIdx = i;
}
break;
}
}
createListFromValues();
}
break;
case REMOVE_PKG:
if(!mDoneIniting) {
//insert message again after some delay
sendMessageToHandler(REMOVE_PKG, data, 10*1000);
break;
}
pkgName = data.getString(ATTR_PKG_NAME);
removePackageFromAppList(pkgName);
if(mSizeMap.remove(pkgName) == null) {
Log.i(TAG, "Coudnt remove from size map package:"+pkgName);
}
if(mAppAdapterMap.remove(pkgName) == null) {
Log.i(TAG, "Coudnt remove from app adapter map package:"+pkgName);
}
if(mCurrentPkg.packageName.equalsIgnoreCase(pkgName)) {
if(mCurrentPkgIdx == (mAppList.size()-1)) {
mCurrentPkgIdx--;
}
mCurrentPkg = mAppList.get(mCurrentPkgIdx);
}
createListFromValues();
break;
case REORDER_LIST:
int sortOrder = msg.arg1;
if(sortOrder != mSortOrder) {
mSortOrder = sortOrder;
if(localLOGV) Log.i(TAG, "Changing sort order to "+mSortOrder);
sortAppList();
mCurrentPkgIdx = 0;
mCurrentPkg = mAppList.get(mCurrentPkgIdx);
createListFromValues();
}
break;
case ADD_PKG:
pkgName = data.getString(ATTR_PKG_NAME);
if(!mDoneIniting) {
//insert message again after some delay
sendMessageToHandler(ADD_PKG, data, 10*1000);
break;
}
mObserver.invokeGetSizeInfo(pkgName, false);
break;
default:
break;
}
}
};
private void removePackageFromAppList(String pkgName) {
int size = mAppList.size();
for(int i = 0; i < size; i++) {
if(mAppList.get(i).packageName.equalsIgnoreCase(pkgName)) {
mAppList.remove(i);
break;
}
}
}
private void clearMessages() {
synchronized(mHandler) {
mHandler.removeMessages(COMPUTE_PKG_SIZE_START);
mHandler.removeMessages(COMPUTE_PKG_SIZE_DONE);
mHandler.removeMessages(REMOVE_PKG);
mHandler.removeMessages(REORDER_LIST);
mHandler.removeMessages(ADD_PKG);
}
}
private void sendMessageToHandler(int msgId, Bundle data, long delayMillis) {
synchronized(mHandler) {
Message msg = mHandler.obtainMessage(msgId);
msg.setData(data);
if(delayMillis == 0) {
mHandler.sendMessage(msg);
} else {
mHandler.sendMessageDelayed(msg, delayMillis);
}
}
}
private void sendMessageToHandler(int msgId, int arg1) {
synchronized(mHandler) {
Message msg = mHandler.obtainMessage(msgId);
msg.arg1 = arg1;
mHandler.sendMessage(msg);
}
}
private void sendMessageToHandler(int msgId) {
synchronized(mHandler) {
mHandler.sendEmptyMessage(msgId);
}
}
class PkgSizeObserver extends IPackageStatsObserver.Stub {
public PackageStats ps;
public ApplicationInfo appInfo;
public Drawable appIcon;
public CharSequence appName;
public CharSequence appDesc = "";
private int mIdx = 0;
private boolean mChained = false;
public boolean succeeded;
PkgSizeObserver(int i) {
mIdx = i;
}
private void getAppDetails() {
try {
appInfo = mPm.getApplicationInfo(ps.packageName, 0);
} catch (NameNotFoundException e) {
return;
}
appName = appInfo.loadLabel(mPm);
appIcon = appInfo.loadIcon(mPm);
}
public void onGetStatsCompleted(PackageStats pStats, boolean pSucceeded) {
Bundle data = new Bundle();
ps = pStats;
succeeded = pSucceeded;
if(mChained) {
data.putInt(ATTR_APP_IDX, mIdx);
if(succeeded) {
mIdx++;
}
}
data.putBoolean(ATTR_CHAINED, mChained);
getAppDetails();
if(localLOGV) Log.i(TAG, "onGetStatsCompleted::"+appInfo.packageName+", ("+ps.cacheSize+","+
ps.codeSize+", "+ps.dataSize);
sendMessageToHandler(COMPUTE_PKG_SIZE_DONE, data, 0);
}
public void invokeGetSizeInfo(String packageName, boolean chained) {
mChained = chained;
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, data, 0);
} else if(Intent.ACTION_PACKAGE_REMOVED.equalsIgnoreCase(actionStr)) {
Bundle data = new Bundle();
data.putString(ATTR_PKG_NAME, pkgName);
sendMessageToHandler(REMOVE_PKG, data, 0);
} else if(Intent.ACTION_PACKAGE_CHANGED.equalsIgnoreCase(actionStr)) {
//force adapter to draw the list again. TODO derive from SimpleAdapter
//to avoid this
}
}
/*
* Utility method to create an array of map objects from a map of map objects
* for displaying list items to be used in SimpleAdapter.
*/
private void createListFromValues() {
findViewById(R.id.center_text).setVisibility(View.GONE);
populateAdapterList();
mAppAdapter.setViewBinder(this);
ListView lv= (ListView) findViewById(android.R.id.list);
lv.setOnItemClickListener(this);
lv.setAdapter(mAppAdapter);
if(mCurrentPkgIdx != -1) {
lv.setSelection(mCurrentPkgIdx);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String action = getIntent().getAction();
if(action.equals(Intent.ACTION_MANAGE_PACKAGE_STORAGE)) {
mSortOrder = SORT_ORDER_SIZE;
}
mPm = getPackageManager();
//load strings from resources
mBStr = getString(R.string.b_text);
mKbStr = getString(R.string.kb_text);
mMbStr = getString(R.string.mb_text);
}
@Override
public void onStart() {
super.onStart();
setContentView(R.layout.compute_sizes);
//clear all messages related to application list
clearMessages();
sendMessageToHandler(COMPUTE_PKG_SIZE_START);
}
@Override
public void onStop() {
super.onStop();
//register receiver here
unregisterReceiver(mReceiver);
}
public static class AppInfoComparator implements Comparator<ApplicationInfo> {
public AppInfoComparator(HashMap<String, PackageStats> pSizeMap) {
mSizeMap= pSizeMap;
}
public final int compare(ApplicationInfo a, ApplicationInfo b) {
PackageStats aps, bps;
aps = mSizeMap.get(a.packageName);
bps = mSizeMap.get(b.packageName);
if (aps == null && bps == null) {
return 0;
} else if (aps == null) {
return 1;
} else if (bps == null) {
return -1;
}
long atotal = aps.dataSize+aps.codeSize+aps.cacheSize;
long btotal = bps.dataSize+bps.codeSize+bps.cacheSize;
long ret = atotal-btotal;
//negate result to sort in descending order
if(ret < 0) {
return 1;
}
if(ret == 0) {
return 0;
}
return -1;
}
private HashMap<String, PackageStats> mSizeMap;
}
/*
* Have to extract elements form map and populate a list ot be used by
* SimpleAdapter when displaying list elements. The sort order has to follow
* the order of elements in mAppList.
*/
private List<Map<String, ?>> createAdapterListFromMap() {
//get the index from mAppInfo which gives the correct sort position
int imax = mAppList.size();
if(localLOGV) Log.i(TAG, "Creating new adapter list");
List<Map<String, ?>> adapterList = new ArrayList<Map<String, ?>>();
ApplicationInfo tmpInfo;
for(int i = 0; i < imax; i++) {
tmpInfo = mAppList.get(i);
Map<String, Object>newObj = new TreeMap<String, Object>(
mAppAdapterMap.get(tmpInfo.packageName));
adapterList.add(newObj);
}
return adapterList;
}
private void populateAdapterList() {
mAppAdapter = new SimpleAdapter(this, createAdapterListFromMap(),
R.layout.manage_applications_item, sKeys, sResourceIds);
}
private String getSizeStr(PackageStats ps) {
String retStr = "";
//insert total size information into map to display in view
//at this point its guaranteed that ps is not null. but checking anyway
if(ps != null) {
long size = ps.cacheSize+ps.codeSize+ps.dataSize;
if(size < 1024) {
return String.valueOf(size)+mBStr;
}
long kb, mb, rem;
kb = size >> 10;
rem = size - (kb << 10);
if(kb < 1024) {
if(rem > 512) {
kb++;
}
retStr += String.valueOf(kb)+mKbStr;
return retStr;
}
mb = kb >> 10;
if(kb >= 512) {
//round off
mb++;
}
retStr += String.valueOf(mb)+ mMbStr;
return retStr;
} else {
Log.w(TAG, "Something fishy, cannot find size info for package:"+ps.packageName);
}
return retStr;
}
public void sortAppList() {
// Sort application list
if(mSortOrder == SORT_ORDER_ALPHA) {
Collections.sort(mAppList, new ApplicationInfo.DisplayNameComparator(mPm));
} else if(mSortOrder == SORT_ORDER_SIZE) {
Collections.sort(mAppList, new AppInfoComparator(mSizeMap));
}
}
private Map<String, Object> createMapEntry(CharSequence appName,
Drawable appIcon, CharSequence appDesc, String sizeStr) {
Map<String, Object> map = new TreeMap<String, Object>();
map.put(KEY_APP_NAME, appName);
//the icon cannot be null. if the application hasnt set it, the default icon is returned.
map.put(KEY_APP_ICON, appIcon);
if(appDesc == null) {
appDesc="";
}
map.put(KEY_APP_DESC, appDesc);
map.put(KEY_APP_SIZE, sizeStr);
return map;
}
private void startApplicationDetailsActivity(ApplicationInfo info, PackageStats ps) {
//Create intent to start new activity
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(this, InstalledAppDetails.class);
intent.putExtra(APP_PKG_NAME, info.packageName);
if(localLOGV) Log.i(TAG, "code="+ps.codeSize+", cache="+ps.cacheSize+", data="+ps.dataSize);
intent.putExtra(APP_PKG_SIZE, ps);
if(localLOGV) Log.i(TAG, "Starting sub activity to display info for app:"+info
+" with intent:"+intent);
//start new activity to display extended information
if ((info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
}
startActivityForResult(intent, INSTALLED_APP_DETAILS);
}
public boolean setViewValue(View view, Object data, String textRepresentation) {
if(data == null) {
return false;
}
int id = view.getId();
switch(id) {
case R.id.app_name:
((TextView)view).setText((String)data);
break;
case R.id.app_icon:
((ImageView)view).setImageDrawable((Drawable)data);
break;
case R.id.app_description:
((TextView)view).setText((String)data);
break;
case R.id.app_size:
((TextView)view).setText((String)data);
break;
default:
break;
}
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, SORT_ORDER_ALPHA, 0, R.string.sort_order_alpha)
.setIcon(android.R.drawable.ic_menu_sort_alphabetically);
menu.add(0, SORT_ORDER_SIZE, 0, R.string.sort_order_size)
.setIcon(android.R.drawable.ic_menu_sort_by_size);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(mDoneIniting) {
menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder!= SORT_ORDER_SIZE);
return true;
}
return false;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int menuId = item.getItemId();
sendMessageToHandler(REORDER_LIST, menuId);
return true;
}
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
mCurrentPkgIdx=position;
ApplicationInfo info = mAppList.get(position);
mCurrentPkg = info;
PackageStats ps = mSizeMap.get(info.packageName);
startApplicationDetailsActivity(info, ps);
}
}

View File

@@ -0,0 +1,205 @@
/*
* 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.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;
/**
* Confirm and execute a reset of the device to a clean "just out of the box"
* state. Multiple confirmations are required: first, a general "are you sure
* you want to do this?" prompt, followed by a keyguard pattern trace if the user
* has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING
* ON THE PHONE" prompt. If at any time the phone is allowed to go to sleep, is
* locked, et cetera, then the confirmation sequence is abandoned.
*/
public class MasterClear extends Activity {
private static final int KEYGUARD_REQUEST = 55;
private LayoutInflater mInflater;
private LockPatternUtils mLockUtils;
private View mInitialView;
private Button mInitiateButton;
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"))) {
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()");
}
} else {
Log.w("MasterClear", "Unable to locate ICheckinService");
}
/* 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}
* 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.master_clear_gesture_prompt));
intent.putExtra(ConfirmLockPattern.FOOTER_TEXT,
getText(R.string.master_clear_gesture_explanation));
startActivityForResult(intent, KEYGUARD_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != KEYGUARD_REQUEST) {
return;
}
// If the user entered a valid keyguard trace, present the final
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK) {
establishFinalConfirmationState();
} else {
establishInitialState();
}
}
/**
* If the user clicks to begin the reset sequence, we next require a
* keyguard confirmation if the user has currently enabled one. If there
* is no keyguard available, we simply go to the final confirmation prompt.
*/
private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
public void onClick(View v) {
if (mLockUtils.isLockPatternEnabled()) {
runKeyguardConfirmation();
} else {
establishFinalConfirmationState();
}
}
};
/**
* Configure the UI for the final confirmation interaction
*/
private void establishFinalConfirmationState() {
if (mFinalView == null) {
mFinalView = mInflater.inflate(R.layout.master_clear_final, null);
mFinalButton =
(Button) mFinalView.findViewById(R.id.execute_master_clear);
mFinalButton.setOnClickListener(mFinalClickListener);
}
setContentView(mFinalView);
}
/**
* In its initial state, the activity presents a button for the user to
* 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.
*
* <p>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
* time, then simply reuse the inflated views directly whenever we need
* to change contents.
*/
private void establishInitialState() {
if (mInitialView == null) {
mInitialView = mInflater.inflate(R.layout.master_clear_primary, null);
mInitiateButton =
(Button) mInitialView.findViewById(R.id.initiate_master_clear);
mInitiateButton.setOnClickListener(mInitiateListener);
}
setContentView(mInitialView);
}
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
mInitialView = null;
mFinalView = null;
mInflater = LayoutInflater.from(this);
mLockUtils = new LockPatternUtils(getContentResolver());
establishInitialState();
}
/** Abandon all progress through the confirmation sequence by returning
* to the initial view any time the activity is interrupted (e.g. by
* idle timeout).
*/
@Override
public void onPause() {
super.onPause();
establishInitialState();
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.content.Context;
import android.preference.PreferenceCategory;
import android.util.AttributeSet;
import android.view.View;
import java.util.Map;
public class ProgressCategory extends PreferenceCategory {
private boolean mProgress = false;
public ProgressCategory(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.preference_progress_category);
}
@Override
public void onBindView(View view) {
super.onBindView(view);
View textView = view.findViewById(R.id.scanning_text);
View progressBar = view.findViewById(R.id.scanning_progress);
int visibility = mProgress ? View.VISIBLE : View.INVISIBLE;
textView.setVisibility(visibility);
progressBar.setVisibility(visibility);
}
/**
* Turn on/off the progress indicator and text on the right.
* @param progressOn whether or not the progress should be displayed
*/
public void setProgress(boolean progressOn) {
mProgress = progressOn;
notifyChanged();
}
}

View File

@@ -0,0 +1,260 @@
/*
* 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 android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Proxy;
import android.os.Bundle;
import android.provider.Settings;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* To start the Proxy Selector activity, create the following intent.
*
* <code>
* Intent intent = new Intent();
* intent.setClassName("com.android.browser.ProxySelector");
* startActivity(intent);
* </code>
*
* you can add extra options to the intent by using
*
* <code>
* intent.putExtra(key, value);
* </code>
*
* the extra options are:
*
* button-label: a string label to display for the okay button
* title: the title of the window
* error-text: If not null, will be used as the label of the error message.
*/
public class ProxySelector extends Activity
{
private final static String LOGTAG = "Settings";
EditText mHostnameField;
EditText mPortField;
Button mOKButton;
// Matches blank input, ips, and domain names
private static final String HOSTNAME_REGEXP = "^$|^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*$";
private static final Pattern HOSTNAME_PATTERN;
static {
HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
}
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (android.util.Config.LOGV) Log.v(LOGTAG, "[ProxySelector] onStart");
setContentView(R.layout.proxy);
initView();
populateFields(false);
}
protected void showError(int error) {
new AlertDialog.Builder(this)
.setTitle(R.string.proxy_error)
.setMessage(error)
.setPositiveButton(R.string.proxy_error_dismiss, null)
.show();
}
void initView() {
mHostnameField = (EditText)findViewById(R.id.hostname);
mHostnameField.setOnFocusChangeListener(mOnFocusChangeHandler);
mPortField = (EditText)findViewById(R.id.port);
mPortField.setOnClickListener(mOKHandler);
mPortField.setOnFocusChangeListener(mOnFocusChangeHandler);
mOKButton = (Button)findViewById(R.id.action);
mOKButton.setOnClickListener(mOKHandler);
Button b = (Button)findViewById(R.id.clear);
b.setOnClickListener(mClearHandler);
b = (Button)findViewById(R.id.defaultView);
b.setOnClickListener(mDefaultHandler);
}
void populateFields(boolean useDefault) {
String hostname = null;
int port = -1;
if (useDefault) {
// Use the default proxy settings provided by the carrier
hostname = Proxy.getDefaultHost();
port = Proxy.getDefaultPort();
} else {
// Use the last setting given by the user
hostname = Proxy.getHost(this);
port = Proxy.getPort(this);
}
if (hostname == null) {
hostname = "";
}
mHostnameField.setText(hostname);
String portStr = port == -1 ? "" : Integer.toString(port);
mPortField.setText(portStr);
Intent intent = getIntent();
String buttonLabel = intent.getStringExtra("button-label");
if (!TextUtils.isEmpty(buttonLabel)) {
mOKButton.setText(buttonLabel);
}
String title = intent.getStringExtra("title");
if (!TextUtils.isEmpty(title)) {
setTitle(title);
}
}
/**
* validate syntax of hostname and port entries
* @return 0 on success, string resource ID on failure
*/
int validate(String hostname, String port) {
Matcher match = HOSTNAME_PATTERN.matcher(hostname);
if (!match.matches()) return R.string.proxy_error_invalid_host;
if (hostname.length() > 0 && port.length() == 0) {
return R.string.proxy_error_empty_port;
}
if (port.length() > 0) {
if (hostname.length() == 0) {
return R.string.proxy_error_empty_host_set_port;
}
int portVal = -1;
try {
portVal = Integer.parseInt(port);
} catch (NumberFormatException ex) {
return R.string.proxy_error_invalid_port;
}
if (portVal <= 0 || portVal > 0xFFFF) {
return R.string.proxy_error_invalid_port;
}
}
return 0;
}
/**
* returns true on success, false if the user must correct something
*/
boolean saveToDb() {
String hostname = mHostnameField.getText().toString().trim();
String portStr = mPortField.getText().toString().trim();
int port = -1;
int result = validate(hostname, portStr);
if (result > 0) {
showError(result);
return false;
}
if (portStr.length() > 0) {
try {
port = Integer.parseInt(portStr);
} catch (NumberFormatException ex) {
return false;
}
}
// FIXME: The best solution would be to make a better UI that would
// disable editing of the text boxes if the user chooses to use the
// default settings. i.e. checking a box to always use the default
// carrier. http:/b/issue?id=756480
// FIXME: This currently will not work if the default host is blank and
// the user has cleared the input boxes in order to not use a proxy.
// This is a UI problem and can be solved with some better form
// controls.
// FIXME: If the user types in a proxy that matches the default, should
// we keep that setting? Can be fixed with a new UI.
ContentResolver res = getContentResolver();
if (hostname.equals(Proxy.getDefaultHost())
&& port == Proxy.getDefaultPort()) {
// If the user hit the default button and didn't change any of
// the input boxes, treat it as if the user has not specified a
// proxy.
hostname = null;
}
if (!TextUtils.isEmpty(hostname)) {
hostname += ':' + portStr;
}
Settings.System.putString(res, Settings.System.HTTP_PROXY, hostname);
sendBroadcast(new Intent(Proxy.PROXY_CHANGE_ACTION));
return true;
}
OnClickListener mOKHandler = new OnClickListener() {
public void onClick(View v) {
if (saveToDb()) {
finish();
}
}
};
OnClickListener mClearHandler = new OnClickListener() {
public void onClick(View v) {
mHostnameField.setText("");
mPortField.setText("");
}
};
OnClickListener mDefaultHandler = new OnClickListener() {
public void onClick(View v) {
populateFields(true);
}
};
OnFocusChangeListener mOnFocusChangeHandler = new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
TextView textView = (TextView) v;
Selection.selectAll((Spannable) textView.getText());
}
}
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
/*
* 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.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.util.Log;
import android.widget.Toast;
/**
* Glue class: connects AlarmAlert IntentReceiver to AlarmAlert
* activity. Passes through Alarm ID.
*/
public class SdCardErrorReceiver extends BroadcastReceiver {
private static final String TAG = "SdCardErrorReceiver";
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final int duration = 3500;
if (action.equals(Intent.ACTION_MEDIA_BAD_REMOVAL)) {
Toast.makeText(context, R.string.sdcard_removal_alert_title, duration).show();
} else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTABLE)) {
Toast.makeText(context, R.string.sdcard_unmountable_alert_title, duration).show();
} else {
Log.e(TAG, "unknown intent");
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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));
}
}
}

View File

@@ -0,0 +1,218 @@
/*
* 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.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);
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_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) {
String suffix = null;
// add K or M suffix if size is greater than 1K or 1M
if (size >= 1024) {
suffix = "K";
size /= 1024;
if (size >= 1024) {
suffix = "M";
size /= 1024;
}
}
StringBuilder resultBuffer = new StringBuilder(Long.toString(size));
int commaOffset = resultBuffer.length() - 3;
while (commaOffset > 0) {
resultBuffer.insert(commaOffset, ',');
commaOffset -= 3;
}
if (suffix != null)
resultBuffer.append(suffix);
return resultBuffer.toString();
}
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) {
}
}
};
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;
}

View File

@@ -0,0 +1,281 @@
/*
* 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.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.LocationManager;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.util.Config;
import android.util.Log;
import com.android.internal.widget.LockPatternUtils;
/**
* Gesture lock pattern settings.
*/
public class SecuritySettings extends PreferenceActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
// Lock Settings
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
private static final int CONFIRM_PATTERN_REQUEST_CODE = 55;
private LockPatternUtils mLockPatternUtils;
private CheckBoxPreference mLockEnabled;
private CheckBoxPreference mVisiblePattern;
private Preference mChoosePattern;
private CheckBoxPreference mShowPassword;
// Location Settings
private static final String LOCATION_NETWORK = "location_network";
private static final String LOCATION_GPS = "location_gps";
private CheckBoxPreference mNetwork;
private CheckBoxPreference mGps;
private LocationManager mLocationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.security_settings);
mLockPatternUtils = new LockPatternUtils(getContentResolver());
createPreferenceHierarchy();
// Get the available location providers
mLocationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
updateToggles();
}
private PreferenceScreen createPreferenceHierarchy() {
// Root
PreferenceScreen root = this.getPreferenceScreen();
// Inline preferences
PreferenceCategory inlinePrefCat = new PreferenceCategory(this);
inlinePrefCat.setTitle(R.string.lock_settings_title);
root.addPreference(inlinePrefCat);
// 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);
// visible pattern
mVisiblePattern = new CheckBoxPreference(this);
mVisiblePattern.setKey(KEY_VISIBLE_PATTERN);
mVisiblePattern.setTitle(R.string.lockpattern_settings_enable_visible_pattern_title);
inlinePrefCat.addPreference(mVisiblePattern);
// 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);
PreferenceScreen simLockPreferences = getPreferenceManager()
.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.SimLockSettings");
simLockPreferences.setIntent(intent);
PreferenceCategory simLockCat = new PreferenceCategory(this);
simLockCat.setTitle(R.string.sim_lock_settings_title);
root.addPreference(simLockCat);
simLockCat.addPreference(simLockPreferences);
// Passwords
PreferenceCategory passwordsCat = new PreferenceCategory(this);
passwordsCat.setTitle(R.string.security_passwords_title);
root.addPreference(passwordsCat);
CheckBoxPreference showPassword = mShowPassword = new CheckBoxPreference(this);
showPassword.setKey("show_password");
showPassword.setTitle(R.string.show_password);
showPassword.setSummary(R.string.show_password_summary);
showPassword.setPersistent(false);
passwordsCat.addPreference(showPassword);
return root;
}
@Override
protected void onResume() {
super.onResume();
boolean patternExists = mLockPatternUtils.savedPatternExists();
mLockEnabled.setEnabled(patternExists);
mVisiblePattern.setEnabled(patternExists);
mLockEnabled.setChecked(mLockPatternUtils.isLockPatternEnabled());
mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled());
int chooseStringRes = mLockPatternUtils.savedPatternExists() ?
R.string.lockpattern_settings_change_lock_pattern :
R.string.lockpattern_settings_choose_lock_pattern;
mChoosePattern.setTitle(chooseStringRes);
mShowPassword
.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
final String key = preference.getKey();
if (KEY_LOCK_ENABLED.equals(key)) {
mLockPatternUtils.setLockPatternEnabled(isToggled(preference));
} else if (KEY_VISIBLE_PATTERN.equals(key)) {
mLockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
} else if (preference == mShowPassword) {
Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
mShowPassword.isChecked() ? 1 : 0);
}
return false;
}
/*
* Creates toggles for each available location provider
*/
private void updateToggles() {
String providers = getAllowedProviders();
mNetwork.setChecked(providers.contains(LocationManager.NETWORK_PROVIDER));
mGps.setChecked(providers.contains(LocationManager.GPS_PROVIDER));
}
private void updateProviders() {
String preferredProviders = "";
if (mNetwork.isChecked()) {
preferredProviders += LocationManager.NETWORK_PROVIDER;
}
if (mGps.isChecked()) {
preferredProviders += "," + LocationManager.GPS_PROVIDER;
}
setProviders(preferredProviders);
}
private void setProviders(String providers) {
// Update the system setting LOCATION_PROVIDERS_ALLOWED
Settings.System.putString(getContentResolver(),
Settings.System.LOCATION_PROVIDERS_ALLOWED, providers);
if (Config.LOGV) {
Log.v("Location Accuracy", "Setting LOCATION_PROVIDERS_ALLOWED = " + providers);
}
// Inform the location manager about the changes
mLocationManager.updateProviders();
}
/**
* @return string containing a list of providers that have been enabled for use
*/
private String getAllowedProviders() {
String allowedProviders =
Settings.System.getString(getContentResolver(),
Settings.System.LOCATION_PROVIDERS_ALLOWED);
if (allowedProviders == null) {
allowedProviders = "";
}
return allowedProviders;
}
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (LOCATION_NETWORK.equals(key) || LOCATION_GPS.equals(key)) {
updateProviders();
}
}
private boolean isToggled(Preference pref) {
return ((CheckBoxPreference) pref).isChecked();
}
/**
* 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 (isChecked() && mLockPatternUtils.savedPatternExists()) {
confirmPatternThenDisable();
} else {
super.onClick();
}
}
}
/**
* Launch screen to confirm the existing lock pattern.
* @see #onActivityResult(int, int, android.content.Intent)
*/
private void confirmPatternThenDisable() {
final Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.ConfirmLockPattern");
startActivityForResult(intent, CONFIRM_PATTERN_REQUEST_CODE);
}
/**
* @see #confirmPatternThenDisable
*/
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != CONFIRM_PATTERN_REQUEST_CODE) {
return;
}
if (resultCode == Activity.RESULT_OK) {
mLockPatternUtils.setLockPatternEnabled(false);
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.provider.Settings.System;
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";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
Utils.updatePreferenceToSpecificActivityOrRemove(this, parent, KEY_SYNC_SETTINGS, 0);
}
@Override
protected void onResume() {
findPreference(KEY_CALL_SETTINGS).setEnabled(!isAirplaneMode());
super.onResume();
}
private boolean isAirplaneMode() {
return System.getInt(getContentResolver(),
System.AIRPLANE_MODE_ON, 0) > 0;
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import org.apache.commons.codec.binary.Base64;
/**
* The "dialog" that shows from "License" in the Settings app.
*/
public class SettingsLicenseActivity extends AlertActivity {
private static final String TAG = "SettingsLicenseActivity";
private static final boolean LOGV = false || Config.LOGV;
private static final String DEFAULT_LICENSE_PATH = "/system/etc/NOTICE.html";
private static final String PROPERTY_LICENSE_PATH = "ro.config.license_path";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String fileName = SystemProperties.get(PROPERTY_LICENSE_PATH, DEFAULT_LICENSE_PATH);
if (TextUtils.isEmpty(fileName)) {
Log.e(TAG, "The system property for the license file is empty.");
showErrorAndFinish();
return;
}
FileReader fileReader = null;
StringBuilder data = null;
try {
data = new StringBuilder(2048);
char tmp[] = new char[2048];
int numRead;
fileReader = new FileReader(fileName);
while ((numRead = fileReader.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 (fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
}
}
if (TextUtils.isEmpty(data)) {
Log.e(TAG, "License HTML is empty (from " + fileName + ")");
showErrorAndFinish();
return;
}
WebView webView = new WebView(this);
if (LOGV) Log.v(TAG, "Started encode at " + System.currentTimeMillis());
// Need to encode to base64 for WebView to load the contents properly
String dataStr;
try {
byte[] base64Bytes = Base64.encodeBase64(data.toString().getBytes("ISO8859_1"));
dataStr = new String(base64Bytes);
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Could not convert to base64", e);
showErrorAndFinish();
return;
}
if (LOGV) Log.v(TAG, "Ended encode at " + System.currentTimeMillis());
if (LOGV) {
Log.v(TAG, "Started test decode at " + System.currentTimeMillis());
Base64.decodeBase64(dataStr.getBytes());
Log.v(TAG, "Ended decode at " + System.currentTimeMillis());
}
// Begin the loading. This will be done in a separate thread in WebView.
webView.loadData(dataStr, "text/html", "base64");
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_license_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();
}
}

View File

@@ -0,0 +1,321 @@
/*
* 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.content.Context;
import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceScreen;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import android.widget.Toast;
/**
* Implements the preference screen to enable/disable SIM lock and
* also the dialogs to change the SIM PIN. In the former case, enabling/disabling
* the SIM lock will prompt the user for the current PIN.
* In the Change PIN case, it prompts the user for old pin, new pin and new pin
* again before attempting to change it. Calls the SimCard interface to execute
* these operations.
*
*/
public class SimLockSettings extends PreferenceActivity
implements EditPinPreference.OnPinEnteredListener {
private static final int OFF_MODE = 0;
// State when enabling/disabling SIM lock
private static final int SIM_LOCK_MODE = 1;
// State when entering the old pin
private static final int SIM_OLD_MODE = 2;
// State when entering the new pin - first time
private static final int SIM_NEW_MODE = 3;
// State when entering the new pin - second time
private static final int SIM_REENTER_MODE = 4;
// Keys in xml file
private static final String PIN_DIALOG = "sim_pin";
private static final String PIN_TOGGLE = "sim_toggle";
// Keys in icicle
private static final String DIALOG_STATE = "dialogState";
private static final String DIALOG_PIN = "dialogPin";
private static final String DIALOG_ERROR = "dialogError";
private static final String ENABLE_TO_STATE = "enableState";
private static final int MIN_PIN_LENGTH = 4;
private static final int MAX_PIN_LENGTH = 8;
// Which dialog to show next when popped up
private int mDialogState = OFF_MODE;
private String mPin;
private String mOldPin;
private String mNewPin;
private String mError;
// Are we trying to enable or disable SIM lock?
private boolean mToState;
private Phone mPhone;
private EditPinPreference mPinDialog;
private CheckBoxPreference mPinToggle;
private Resources mRes;
// For async handler to identify request type
private static final int ENABLE_SIM_PIN_COMPLETE = 100;
private static final int CHANGE_SIM_PIN_COMPLETE = 101;
// For replies from SimCard interface
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
switch (msg.what) {
case ENABLE_SIM_PIN_COMPLETE:
simLockChanged(ar.exception == null);
break;
case CHANGE_SIM_PIN_COMPLETE:
simPinChanged(ar.exception == null);
break;
}
return;
}
};
// For top-level settings screen to query
static boolean isSimLockEnabled() {
return PhoneFactory.getDefaultPhone().getSimCard().getSimLockEnabled();
}
static String getSummary(Context context) {
Resources res = context.getResources();
String summary = isSimLockEnabled()
? res.getString(R.string.sim_lock_on)
: res.getString(R.string.sim_lock_off);
return summary;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.sim_lock_settings);
mPinDialog = (EditPinPreference) findPreference(PIN_DIALOG);
mPinToggle = (CheckBoxPreference) findPreference(PIN_TOGGLE);
if (savedInstanceState != null && savedInstanceState.containsKey(DIALOG_STATE)) {
mDialogState = savedInstanceState.getInt(DIALOG_STATE);
mPin = savedInstanceState.getString(DIALOG_PIN);
mError = savedInstanceState.getString(DIALOG_ERROR);
mToState = savedInstanceState.getBoolean(ENABLE_TO_STATE);
}
mPinDialog.setOnPinEnteredListener(this);
// Don't need any changes to be remembered
getPreferenceScreen().setPersistent(false);
mPhone = PhoneFactory.getDefaultPhone();
mRes = getResources();
}
@Override
protected void onResume() {
super.onResume();
mPinToggle.setChecked(mPhone.getSimCard().getSimLockEnabled());
if (mDialogState != OFF_MODE) {
showPinDialog();
} else {
// Prep for standard click on "Change PIN"
resetDialogState();
}
}
@Override
protected void onSaveInstanceState(Bundle out) {
// Need to store this state for slider open/close
// There is one case where the dialog is popped up by the preference
// framework. In that case, let the preference framework store the
// dialog state. In other cases, where this activity manually launches
// the dialog, store the state of the dialog.
if (mPinDialog.isDialogOpen()) {
out.putInt(DIALOG_STATE, mDialogState);
out.putString(DIALOG_PIN, mPinDialog.getEditText().getText().toString());
out.putString(DIALOG_ERROR, mError);
out.putBoolean(ENABLE_TO_STATE, mToState);
} else {
super.onSaveInstanceState(out);
}
}
private void showPinDialog() {
if (mDialogState == OFF_MODE) {
return;
}
setDialogValues();
mPinDialog.showPinDialog();
}
private void setDialogValues() {
mPinDialog.setText(mPin);
String message = "";
switch (mDialogState) {
case SIM_LOCK_MODE:
message = mRes.getString(R.string.sim_enter_pin);
mPinDialog.setDialogTitle(mToState
? mRes.getString(R.string.sim_enable_sim_lock)
: mRes.getString(R.string.sim_disable_sim_lock));
break;
case SIM_OLD_MODE:
message = mRes.getString(R.string.sim_enter_old);
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
break;
case SIM_NEW_MODE:
message = mRes.getString(R.string.sim_enter_new);
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
break;
case SIM_REENTER_MODE:
message = mRes.getString(R.string.sim_reenter_new);
mPinDialog.setDialogTitle(mRes.getString(R.string.sim_change_pin));
break;
}
if (mError != null) {
message = mError + "\n" + message;
mError = null;
}
mPinDialog.setDialogMessage(message);
}
public void onPinEntered(EditPinPreference preference, boolean positiveResult) {
if (!positiveResult) {
resetDialogState();
return;
}
mPin = preference.getText();
if (!reasonablePin(mPin)) {
// inject error message and display dialog again
mError = mRes.getString(R.string.sim_bad_pin);
showPinDialog();
return;
}
switch (mDialogState) {
case SIM_LOCK_MODE:
tryChangeSimLockState();
break;
case SIM_OLD_MODE:
mOldPin = mPin;
mDialogState = SIM_NEW_MODE;
mError = null;
mPin = null;
showPinDialog();
break;
case SIM_NEW_MODE:
mNewPin = mPin;
mDialogState = SIM_REENTER_MODE;
mPin = null;
showPinDialog();
break;
case SIM_REENTER_MODE:
if (!mPin.equals(mNewPin)) {
mError = mRes.getString(R.string.sim_pins_dont_match);
mDialogState = SIM_NEW_MODE;
mPin = null;
showPinDialog();
} else {
mError = null;
tryChangePin();
}
break;
}
}
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mPinToggle) {
// Get the new, preferred state
mToState = mPinToggle.isChecked();
// Flip it back and pop up pin dialog
mPinToggle.setChecked(!mToState);
mDialogState = SIM_LOCK_MODE;
showPinDialog();
}
return true;
}
private void tryChangeSimLockState() {
// Try to change sim lock. If it succeeds, toggle the lock state and
// reset dialog state. Else inject error message and show dialog again.
Message callback = Message.obtain(mHandler, ENABLE_SIM_PIN_COMPLETE);
mPhone.getSimCard().setSimLockEnabled(mToState, mPin, callback);
}
private void simLockChanged(boolean success) {
if (success) {
mPinToggle.setChecked(mToState);
} else {
// TODO: I18N
Toast.makeText(this, mRes.getString(R.string.sim_lock_failed), Toast.LENGTH_SHORT)
.show();
}
resetDialogState();
}
private void simPinChanged(boolean success) {
if (!success) {
// TODO: I18N
Toast.makeText(this, mRes.getString(R.string.sim_change_failed),
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(this, mRes.getString(R.string.sim_change_succeeded),
Toast.LENGTH_SHORT)
.show();
}
resetDialogState();
}
private void tryChangePin() {
Message callback = Message.obtain(mHandler, CHANGE_SIM_PIN_COMPLETE);
mPhone.getSimCard().changeSimLockPassword(mOldPin,
mNewPin, callback);
}
private boolean reasonablePin(String pin) {
if (pin == null || pin.length() < MIN_PIN_LENGTH || pin.length() > MAX_PIN_LENGTH) {
return false;
} else {
return true;
}
}
private void resetDialogState() {
mError = null;
mDialogState = SIM_OLD_MODE; // Default for when Change PIN is clicked
mPin = "";
setDialogValues();
}
}

View File

@@ -0,0 +1,172 @@
/*
* 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 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.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;
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 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 CheckBoxPreference mSilent;
private CheckBoxPreference mVibrate;
private CheckBoxPreference mDtmfTone;
private CheckBoxPreference mSoundEffects;
private AudioManager mAudioManager;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int ringerMode = intent
.getIntExtra(AudioManager.EXTRA_RINGER_MODE, AudioManager.RINGER_MODE_NORMAL);
boolean isSilentMode = ringerMode != AudioManager.RINGER_MODE_NORMAL;
if (mSilent.isChecked() != isSilentMode) {
mSilent.setChecked(isSilentMode);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ContentResolver resolver = getContentResolver();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
addPreferencesFromResource(R.xml.sound_and_display_settings);
mSilent = (CheckBoxPreference) findPreference(KEY_SILENT);
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);
ListPreference screenTimeoutPreference =
(ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
getContentResolver(), SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
screenTimeoutPreference.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 boolean silent = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
final boolean phoneVibrate = mAudioManager
.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER)
== AudioManager.VIBRATE_SETTING_ON;
if (silent != mSilent.isChecked() || force) {
mSilent.setChecked(silent);
}
if (phoneVibrate != mVibrate.isChecked() || force) {
mVibrate.setChecked(phoneVibrate);
}
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mSilent) {
final boolean silent = mSilent.isChecked();
mAudioManager.setRingerMode(silent ? AudioManager.RINGER_MODE_SILENT
: AudioManager.RINGER_MODE_NORMAL);
} else if (preference == mVibrate) {
final boolean vibrate = mVibrate.isChecked();
mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
vibrate ? AudioManager.VIBRATE_SETTING_ON
: AudioManager.VIBRATE_SETTING_OFF);
} else if (preference == mDtmfTone) {
Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
mDtmfTone.isChecked() ? 1 : 0);
} else if (preference == mSoundEffects) {
if (mSoundEffects.isChecked()) {
mAudioManager.loadSoundEffects();
} else {
mAudioManager.unloadSoundEffects();
}
Settings.System.putInt(getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED,
mSoundEffects.isChecked() ? 1 : 0);
}
return true;
}
public boolean onPreferenceChange(Preference preference, Object objValue) {
if (KEY_SCREEN_TIMEOUT.equals(preference.getKey())) {
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;
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.os.Bundle;
import android.preference.PreferenceActivity;
public class TestingSettings extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.testing_settings);
}
}

View File

@@ -0,0 +1,28 @@
package com.android.settings;
import android.provider.Telephony;
import static android.provider.Telephony.Intents.SECRET_CODE_ACTION;
import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.util.Config;
import android.util.Log;
import android.view.KeyEvent;
public class TestingSettingsBroadcastReceiver extends BroadcastReceiver {
public TestingSettingsBroadcastReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SECRET_CODE_ACTION)) {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setClass(context, TestingSettings.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}

View File

@@ -0,0 +1,91 @@
/**
* Copyright (C) 2007 Google Inc.
*
* 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.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import java.util.List;
public class Utils {
/**
* Set the preference's title to the matching activity's label.
*/
public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1;
/**
* Finds a matching activity for a preference's intent. If a matching
* activity is not found, it will remove the preference.
*
* @param context The context.
* @param parentPreferenceGroup The preference group that contains the
* preference whose intent is being resolved.
* @param preferenceKey The key of the preference whose intent is being
* resolved.
* @param flags 0 or one or more of
* {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY}
* .
* @return Whether an activity was found. If false, the preference was
* removed.
*/
public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
if (preference == null) {
return false;
}
Intent intent = preference.getIntent();
if (intent != null) {
// Find the activity that is in the system image
PackageManager pm = context.getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
ResolveInfo resolveInfo = list.get(i);
if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
!= 0) {
// Replace the intent with this specific activity
preference.setIntent(new Intent().setClassName(
resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name));
if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) {
// Set the preference title to the activity's label
preference.setTitle(resolveInfo.loadLabel(pm));
}
return true;
}
}
}
// Did not find a matching activity, so remove the preference
parentPreferenceGroup.removePreference(preference);
return true;
}
}

View File

@@ -0,0 +1,210 @@
/*
* 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.wifi.WifiEnabler;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDeviceCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.widget.Toast;
public class WirelessSettings extends PreferenceActivity {
private static final String KEY_TOGGLE_AIRPLANE = "toggle_airplane";
private static final String KEY_TOGGLE_BLUETOOTH = "toggle_bluetooth";
private static final String KEY_TOGGLE_WIFI = "toggle_wifi";
private WifiEnabler mWifiEnabler;
private AirplaneModeEnabler mAirplaneModeEnabler;
private CheckBoxPreference mToggleBluetooth;
private IntentFilter mIntentFilter;
private static final int EVENT_FAILED_BT_ENABLE = 1;
private static final int EVENT_PASSED_BT_ENABLE = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wireless_settings);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(BluetoothIntent.ENABLED_ACTION);
mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION);
initToggles();
}
@Override
protected void onResume() {
super.onResume();
refreshToggles();
registerReceiver(mReceiver, mIntentFilter);
mWifiEnabler.resume();
mAirplaneModeEnabler.resume();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
mWifiEnabler.pause();
mAirplaneModeEnabler.pause();
}
private void initToggles() {
mWifiEnabler = new WifiEnabler(
this,
(WifiManager) getSystemService(WIFI_SERVICE),
(CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI));
mAirplaneModeEnabler = new AirplaneModeEnabler(
this,
(CheckBoxPreference) findPreference(KEY_TOGGLE_AIRPLANE));
mToggleBluetooth = (CheckBoxPreference) findPreference(KEY_TOGGLE_BLUETOOTH);
mToggleBluetooth.setPersistent(false);
}
private void refreshToggles() {
mToggleBluetooth.setChecked(isBluetoothEnabled());
mToggleBluetooth.setEnabled(true);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mToggleBluetooth) {
setBluetoothEnabled(mToggleBluetooth.isChecked());
return true;
}
return false;
}
private boolean isBluetoothEnabled() {
BluetoothDevice device = (BluetoothDevice)getSystemService(BLUETOOTH_SERVICE);
if (device != null) {
return device.isEnabled();
} else {
return false;
}
}
private void setBluetoothEnabled(boolean enabled) {
try {
BluetoothDevice device = (BluetoothDevice)getSystemService(BLUETOOTH_SERVICE);
if (enabled) {
// Turn it off until intent or callback is delivered
mToggleBluetooth.setChecked(false);
if (device.enable(mBtCallback)) {
mToggleBluetooth.setSummary(R.string.bluetooth_enabling);
mToggleBluetooth.setEnabled(false);
}
} else {
if (device.disable()) {
Settings.System.putInt(getContentResolver(),
Settings.System.BLUETOOTH_ON, 0);
} else {
// Unusual situation, that you can't turn off bluetooth
mToggleBluetooth.setChecked(true);
}
}
} catch (NullPointerException e) {
// TODO: 1071858
mToggleBluetooth.setChecked(false);
mToggleBluetooth.setEnabled(false);
}
}
private IBluetoothDeviceCallback mBtCallback = new IBluetoothDeviceCallback.Stub() {
public void onEnableResult(int res) {
switch (res) {
case BluetoothDevice.RESULT_FAILURE:
mHandler.sendMessage(mHandler.obtainMessage(EVENT_FAILED_BT_ENABLE, 0));
break;
case BluetoothDevice.RESULT_SUCCESS:
mHandler.sendMessage(mHandler.obtainMessage(EVENT_PASSED_BT_ENABLE, 0));
break;
}
}
public void onCreateBondingResult(String device, int res) {
// Don't care
}
public void onGetRemoteServiceChannelResult(String address, int channel) { }
};
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
updateBtStatus(true);
} else if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
mToggleBluetooth.setChecked(false);
}
}
};
private void updateBtStatus(boolean enabled) {
mToggleBluetooth.setChecked(enabled);
mToggleBluetooth.setEnabled(true);
mToggleBluetooth.setSummary(R.string.bluetooth_quick_toggle_summary);
if (enabled) {
Settings.System.putInt(getContentResolver(),
Settings.System.BLUETOOTH_ON, 1);
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_PASSED_BT_ENABLE:
updateBtStatus(true);
break;
case EVENT_FAILED_BT_ENABLE:
updateBtStatus(false);
Toast.makeText(WirelessSettings.this,
getResources().getString(R.string.bluetooth_failed_to_enable),
Toast.LENGTH_SHORT).show();
break;
}
}
};
}

View File

@@ -0,0 +1,273 @@
/*
* 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 android.app.AlarmManager;
import android.app.ListActivity;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
/**
* This activity displays a list of time zones that match a filter string
* such as "Africa", "Europe", etc. Choosing an item from the list will set
* the time zone. Pressing Back without choosing from the list will not
* result in a change in the time zone setting.
*/
public class ZoneList extends ListActivity {
private static final String TAG = "ZoneList";
private static final String KEY_ID = "id";
private static final String KEY_DISPLAYNAME = "name";
private static final String KEY_GMT = "gmt";
private static final String KEY_OFFSET = "offset";
private static final String XMLTAG_TIMEZONE = "timezone";
private static final int HOURS_1 = 60 * 60000;
private static final int HOURS_24 = 24 * HOURS_1;
private static final int HOURS_HALF = HOURS_1 / 2;
private static final int MENU_TIMEZONE = Menu.FIRST+1;
private static final int MENU_ALPHABETICAL = Menu.FIRST;
// Initial focus position
private int mDefault;
private boolean mSortedByTimezone;
private SimpleAdapter mTimezoneSortedAdapter;
private SimpleAdapter mAlphabeticalAdapter;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
String[] from = new String[] {KEY_DISPLAYNAME, KEY_GMT};
int[] to = new int[] {android.R.id.text1, android.R.id.text2};
MyComparator comparator = new MyComparator(KEY_OFFSET);
List<HashMap> timezoneSortedList = getZones();
Collections.sort(timezoneSortedList, comparator);
mTimezoneSortedAdapter = new SimpleAdapter(this,
(List) timezoneSortedList,
android.R.layout.simple_list_item_2,
from,
to);
List<HashMap> alphabeticalList = new ArrayList<HashMap>(timezoneSortedList);
comparator.setSortingKey(KEY_DISPLAYNAME);
Collections.sort(alphabeticalList, comparator);
mAlphabeticalAdapter = new SimpleAdapter(this,
(List) alphabeticalList,
android.R.layout.simple_list_item_2,
from,
to);
// Sets the adapter
setSorting(true);
// If current timezone is in this list, move focus to it
setSelection(mDefault);
// Assume user may press Back
setResult(RESULT_CANCELED);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_ALPHABETICAL, 0, R.string.zone_list_menu_sort_alphabetically)
.setIcon(R.drawable.ic_menu_sort_alphabetically);
menu.add(0, MENU_TIMEZONE, 0, R.string.zone_list_menu_sort_by_timezone)
.setIcon(R.drawable.ic_menu_3d_globe);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (mSortedByTimezone) {
menu.findItem(MENU_TIMEZONE).setVisible(false);
menu.findItem(MENU_ALPHABETICAL).setVisible(true);
} else {
menu.findItem(MENU_TIMEZONE).setVisible(true);
menu.findItem(MENU_ALPHABETICAL).setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_TIMEZONE:
setSorting(true);
return true;
case MENU_ALPHABETICAL:
setSorting(false);
return true;
default:
return false;
}
}
private void setSorting(boolean timezone) {
setListAdapter(timezone ? mTimezoneSortedAdapter : mAlphabeticalAdapter);
mSortedByTimezone = timezone;
}
private List<HashMap> getZones() {
List<HashMap> myData = new ArrayList<HashMap>();
long date = Calendar.getInstance().getTimeInMillis();
try {
XmlResourceParser xrp = getResources().getXml(R.xml.timezones);
while (xrp.next() != XmlResourceParser.START_TAG)
;
xrp.next();
while (xrp.getEventType() != XmlResourceParser.END_TAG) {
while (xrp.getEventType() != XmlResourceParser.START_TAG) {
if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) {
return myData;
}
xrp.next();
}
if (xrp.getName().equals(XMLTAG_TIMEZONE)) {
String id = xrp.getAttributeValue(0);
String displayName = xrp.nextText();
addItem(myData, id, displayName, date);
}
while (xrp.getEventType() != XmlResourceParser.END_TAG) {
xrp.next();
}
xrp.next();
}
xrp.close();
} catch (XmlPullParserException xppe) {
Log.e(TAG, "Ill-formatted timezones.xml file");
} catch (java.io.IOException ioe) {
Log.e(TAG, "Unable to read timezones.xml file");
}
return myData;
}
protected void addItem(List<HashMap> myData, String id, String displayName,
long date) {
HashMap map = new HashMap();
map.put(KEY_ID, id);
map.put(KEY_DISPLAYNAME, displayName);
TimeZone tz = TimeZone.getTimeZone(id);
int offset = tz.getOffset(date);
int p = Math.abs(offset);
StringBuilder name = new StringBuilder();
name.append("GMT");
if (offset < 0) {
name.append('-');
} else {
name.append('+');
}
name.append(p / (HOURS_1));
name.append(':');
int min = p / 60000;
min %= 60;
if (min < 10) {
name.append('0');
}
name.append(min);
map.put(KEY_GMT, name.toString());
map.put(KEY_OFFSET, offset);
if (id.equals(TimeZone.getDefault().getID())) {
mDefault = myData.size();
}
myData.add(map);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Map map = (Map) l.getItemAtPosition(position);
// Update the system timezone value
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setTimeZone((String) map.get(KEY_ID));
setResult(RESULT_OK);
finish();
}
private static class MyComparator implements Comparator<HashMap> {
private String mSortingKey;
public MyComparator(String sortingKey) {
mSortingKey = sortingKey;
}
public void setSortingKey(String sortingKey) {
mSortingKey = sortingKey;
}
public int compare(HashMap map1, HashMap map2) {
Object value1 = map1.get(mSortingKey);
Object value2 = map2.get(mSortingKey);
/*
* This should never happen, but just in-case, put non-comparable
* items at the end.
*/
if (!isComparable(value1)) {
return isComparable(value2) ? 1 : 0;
} else if (!isComparable(value2)) {
return -1;
}
return ((Comparable) value1).compareTo(value2);
}
private boolean isComparable(Object value) {
return (value != null) && (value instanceof Comparable);
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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 android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZonePicker extends ListActivity {
private ArrayAdapter<CharSequence> mFilterAdapter;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mFilterAdapter = ArrayAdapter.createFromResource(this,
R.array.timezone_filters, android.R.layout.simple_list_item_1);
setListAdapter(mFilterAdapter);
}
protected void addItem(List<Map> data, String name, String zone) {
HashMap temp = new HashMap();
temp.put("title", name);
temp.put("zone", zone);
data.add(temp);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
String filter = (String) mFilterAdapter.getItem(position);
// If All is chosen, reset the filter
if (filter.equals("All")) {
filter = null;
}
Intent zoneList = new Intent();
zoneList.setClass(this, ZoneList.class);
zoneList.putExtra("filter", filter);
startActivityForResult(zoneList, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// If subactivity has resulted in a timezone selection, close this act.
if (resultCode == RESULT_OK) {
finish();
}
}
}

View File

@@ -0,0 +1,178 @@
/*
* 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.deviceinfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
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.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import com.android.settings.R;
import java.io.File;
import java.text.DecimalFormat;
public class Memory extends PreferenceActivity {
private static final String MEMORY_SD_SIZE = "memory_sd_size";
private static final String MEMORY_SD_AVAIL = "memory_sd_avail";
private static final String MEMORY_SD_UNMOUNT = "memory_sd_unmount";
private Resources mRes;
private Preference mSdSize;
private Preference mSdAvail;
private Preference mSdUnmount;
private IMountService mMountService;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.device_info_memory);
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
mRes = getResources();
mSdSize = findPreference(MEMORY_SD_SIZE);
mSdAvail = findPreference(MEMORY_SD_AVAIL);
mSdUnmount = findPreference(MEMORY_SD_UNMOUNT);
}
@Override
protected void onResume() {
super.onResume();
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_BAD_REMOVAL);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addDataScheme("file");
registerReceiver(mReceiver, intentFilter);
updateMemoryStatus();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mSdUnmount) {
unmount();
return true;
}
return false;
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateMemoryStatus();
}
};
private void unmount() {
try {
mMountService.unmountMedia(Environment.getExternalStorageDirectory().toString());
} catch (RemoteException ex) {
// Failed for some reason, try to update UI to actual state
updateMemoryStatus();
}
}
private void updateMemoryStatus() {
String status = Environment.getExternalStorageState();
String readOnly = "";
if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
status = Environment.MEDIA_MOUNTED;
readOnly = mRes.getString(R.string.read_only);
}
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();
mSdSize.setSummary(formatSize(totalBlocks * blockSize));
mSdAvail.setSummary(formatSize(availableBlocks * blockSize) + readOnly);
mSdUnmount.setEnabled(true);
} 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;
}
} else {
mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
mSdUnmount.setEnabled(false);
}
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
findPreference("memory_internal_avail").setSummary(formatSize(availableBlocks * blockSize));
}
private String formatSize(long size) {
String suffix = null;
// add KB or MB suffix if size is greater than 1K or 1M
if (size >= 1024) {
suffix = " KB";
size /= 1024;
if (size >= 1024) {
suffix = " MB";
size /= 1024;
}
}
DecimalFormat formatter = new DecimalFormat();
formatter.setGroupingSize(3);
String result = formatter.format(size);
if (suffix != null)
result = result + suffix;
return result;
}
}

View File

@@ -0,0 +1,378 @@
/*
* 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.deviceinfo;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
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.settings.R;
import java.lang.ref.WeakReference;
/**
* Display the following information
* # Phone Number
* # Network
* # Roaming
* # IMEI
* # IMSI
* # Network type
* # Signal Strength
* # Battery Strength : TODO
* # Uptime
* # Awake Time
* # XMPP/buzz/tickle status : TODO
*
*/
public class Status extends PreferenceActivity {
private static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address";
private static final String KEY_BT_ADDRESS = "bt_address";
private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 200;
private static final int EVENT_SERVICE_STATE_CHANGED = 300;
private static final int EVENT_FIX_UPTIME = 500;
private TelephonyManager mTelephonyManager;
private Phone mPhone = null;
private PhoneStateIntentReceiver mPhoneStateReceiver;
private Resources mRes;
private Preference mSignalStrength;
private Preference mUptime;
private Preference mAwakeTime;
private static String sUnknown;
private Preference mBatteryStatus;
private Preference mBatteryLevel;
private Handler mHandler;
private static class MyHandler extends Handler {
private WeakReference<Status> mStatus;
public MyHandler(Status activity) {
mStatus = new WeakReference<Status>(activity);
}
@Override
public void handleMessage(Message msg) {
Status status = mStatus.get();
if (status == null) {
return;
}
switch (msg.what) {
case EVENT_SIGNAL_STRENGTH_CHANGED:
status.updateSignalStrength();
break;
case EVENT_SERVICE_STATE_CHANGED:
ServiceState serviceState = status.mPhoneStateReceiver.getServiceState();
status.updateServiceState(serviceState);
break;
case EVENT_FIX_UPTIME:
status.updateTimes();
sendMessageDelayed(obtainMessage(EVENT_FIX_UPTIME), 1000);
break;
}
}
}
private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
int level = intent.getIntExtra("level", 0);
int scale = intent.getIntExtra("scale", 100);
mBatteryLevel.setSummary(String.valueOf(level * 100 / scale) + "%");
int plugType = intent.getIntExtra("plugged", 0);
int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
String statusString;
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
statusString = getString(R.string.battery_info_status_charging);
if (plugType > 0) {
statusString = statusString + " " + getString(
(plugType == BatteryManager.BATTERY_PLUGGED_AC)
? R.string.battery_info_status_charging_ac
: R.string.battery_info_status_charging_usb);
}
} else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
statusString = getString(R.string.battery_info_status_discharging);
} else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
statusString = getString(R.string.battery_info_status_not_charging);
} else if (status == BatteryManager.BATTERY_STATUS_FULL) {
statusString = getString(R.string.battery_info_status_full);
} else {
statusString = getString(R.string.battery_info_status_unknown);
}
mBatteryStatus.setSummary(statusString);
}
}
};
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onDataConnectionStateChanged(int state) {
updateDataState();
updateNetworkType();
}
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mHandler = new MyHandler(this);
mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
addPreferencesFromResource(R.xml.device_info_status);
mBatteryLevel = findPreference("battery_level");
mBatteryStatus = findPreference("battery_status");
mRes = getResources();
if (sUnknown == null) {
sUnknown = mRes.getString(R.string.device_info_default);
}
mPhone = PhoneFactory.getDefaultPhone();
mSignalStrength = findPreference("signal_strength");
mUptime = findPreference("up_time");
mAwakeTime = findPreference("awake_time");
setSummaryText("imei", mPhone.getDeviceId());
setSummaryText("imei_sv",
((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
.getDeviceSoftwareVersion());
setSummaryText("imsi", mPhone.getSubscriberId());
setSummaryText("number", mPhone.getLine1Number());
mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
mPhoneStateReceiver.notifySignalStrength(EVENT_SIGNAL_STRENGTH_CHANGED);
mPhoneStateReceiver.notifyServiceState(EVENT_SERVICE_STATE_CHANGED);
setWifiStatus();
setBtStatus();
}
@Override
protected void onResume() {
super.onResume();
mPhoneStateReceiver.registerIntent();
registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
updateSignalStrength();
updateServiceState(mPhone.getServiceState());
updateDataState();
mTelephonyManager.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_FIX_UPTIME), 0);
}
@Override
public void onPause() {
super.onPause();
mPhoneStateReceiver.unregisterIntent();
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
unregisterReceiver(mBatteryInfoReceiver);
mHandler.removeMessages(EVENT_FIX_UPTIME);
}
/**
* @param preference The key for the Preference item
* @param property The system property to fetch
* @param alt The default value, if the property doesn't exist
*/
private void setSummary(String preference, String property, String alt) {
try {
findPreference(preference).setSummary(
SystemProperties.get(property, alt));
} catch (RuntimeException e) {
}
}
private void setSummaryText(String preference, String text) {
if (text != null) {
findPreference(preference).setSummary(text);
}
}
private void updateNetworkType() {
// Whether EDGE, UMTS, etc...
setSummary("network_type", TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, sUnknown);
}
private void updateDataState() {
int state = mTelephonyManager.getDataState();
String display = mRes.getString(R.string.radioInfo_unknown);
switch (state) {
case TelephonyManager.DATA_CONNECTED:
display = mRes.getString(R.string.radioInfo_data_connected);
break;
case TelephonyManager.DATA_SUSPENDED:
display = mRes.getString(R.string.radioInfo_data_suspended);
break;
case TelephonyManager.DATA_CONNECTING:
display = mRes.getString(R.string.radioInfo_data_connecting);
break;
case TelephonyManager.DATA_DISCONNECTED:
display = mRes.getString(R.string.radioInfo_data_disconnected);
break;
}
setSummaryText("data_state", display);
}
private void updateServiceState(ServiceState serviceState) {
int state = serviceState.getState();
String display = mRes.getString(R.string.radioInfo_unknown);
switch (state) {
case ServiceState.STATE_IN_SERVICE:
display = mRes.getString(R.string.radioInfo_service_in);
break;
case ServiceState.STATE_OUT_OF_SERVICE:
case ServiceState.STATE_EMERGENCY_ONLY:
display = mRes.getString(R.string.radioInfo_service_out);
break;
case ServiceState.STATE_POWER_OFF:
display = mRes.getString(R.string.radioInfo_service_off);
break;
}
setSummaryText("service_state", display);
if (serviceState.getRoaming()) {
setSummaryText("roaming_state", mRes.getString(R.string.radioInfo_roaming_in));
} else {
setSummaryText("roaming_state", mRes.getString(R.string.radioInfo_roaming_not));
}
setSummaryText("operator_name", serviceState.getOperatorAlphaLong());
}
void updateSignalStrength() {
int state =
mPhoneStateReceiver.getServiceState().getState();
Resources r = getResources();
if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
(ServiceState.STATE_POWER_OFF == state)) {
mSignalStrength.setSummary("0");
}
int signalDbm = mPhoneStateReceiver.getSignalStrengthDbm();
if (-1 == signalDbm) signalDbm = 0;
int signalAsu = mPhoneStateReceiver.getSignalStrength();
if (-1 == signalAsu) signalAsu = 0;
mSignalStrength.setSummary(String.valueOf(signalDbm) + " "
+ r.getString(R.string.radioInfo_display_dbm) + " "
+ String.valueOf(signalAsu) + " "
+ r.getString(R.string.radioInfo_display_asu));
}
private void setWifiStatus() {
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
Preference wifiMacAddressPref = findPreference(KEY_WIFI_MAC_ADDRESS);
String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress
: getString(R.string.status_unavailable));
}
private void setBtStatus() {
BluetoothDevice bluetooth = (BluetoothDevice) getSystemService(BLUETOOTH_SERVICE);
Preference btAddressPref = findPreference(KEY_BT_ADDRESS);
if (bluetooth == null) {
// device not BT capable
getPreferenceScreen().removePreference(btAddressPref);
} else {
String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null;
btAddressPref.setSummary(!TextUtils.isEmpty(address) ? address
: getString(R.string.status_unavailable));
}
}
void updateTimes() {
long at = SystemClock.uptimeMillis() / 1000;
long ut = SystemClock.elapsedRealtime() / 1000;
long st = ut - at;
if (ut == 0) {
ut = 1;
}
mUptime.setSummary(convert(ut));
mAwakeTime.setSummary(convert(at) + " (" + (((1000 * at / ut) + 5) / 10) + "%)");
}
private String pad(int n) {
if (n >= 10) {
return String.valueOf(n);
} else {
return "0" + String.valueOf(n);
}
}
private String convert(long t) {
int s = (int)(t % 60);
int m = (int)((t / 60) % 60);
int h = (int)((t / 3600));
return h + ":" + pad(m) + ":" + pad(s);
}
}

View File

@@ -0,0 +1,331 @@
/*
* 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.quicklaunch;
import com.android.settings.R;
import android.app.ListActivity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Activity to pick a bookmark that will be returned to the caller.
* <p>
* Currently, bookmarks are either:
* <li> Activities that are in the launcher
* <li> Activities that are within an app that is capable of being launched with
* the {@link Intent#ACTION_CREATE_SHORTCUT}.
*/
public class BookmarkPicker extends ListActivity implements SimpleAdapter.ViewBinder {
private static final String TAG = "BookmarkPicker";
/** Extra in the returned intent from this activity. */
public static final String EXTRA_TITLE = "com.android.settings.quicklaunch.TITLE";
/** Extra that should be provided, and will be returned. */
public static final String EXTRA_SHORTCUT = "com.android.settings.quicklaunch.SHORTCUT";
/**
* The request code for the screen to create a bookmark that is WITHIN an
* application. For example, Gmail can return a bookmark for the inbox
* folder.
*/
private static final int REQUEST_CREATE_SHORTCUT = 1;
/** Intent used to get all the activities that are launch-able */
private static Intent sLaunchIntent;
/** Intent used to get all the activities that are {@link #REQUEST_CREATE_SHORTCUT}-able */
private static Intent sShortcutIntent;
/**
* List of ResolveInfo for activities that we can bookmark (either directly
* to the activity, or by launching the activity and it returning a bookmark
* WITHIN that application).
*/
private List<ResolveInfo> mResolveList;
// List adapter stuff
private static final String KEY_TITLE = "TITLE";
private static final String KEY_RESOLVE_INFO = "RESOLVE_INFO";
private static final String sKeys[] = new String[] { KEY_TITLE, KEY_RESOLVE_INFO };
private static final int sResourceIds[] = new int[] { R.id.title, R.id.icon };
private SimpleAdapter mMyAdapter;
/** Display those activities that are launch-able */
private static final int DISPLAY_MODE_LAUNCH = 0;
/** Display those activities that are able to have bookmarks WITHIN the application */
private static final int DISPLAY_MODE_SHORTCUT = 1;
private int mDisplayMode = DISPLAY_MODE_LAUNCH;
private Handler mUiHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
updateListAndAdapter();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, DISPLAY_MODE_LAUNCH, 0, R.string.quick_launch_display_mode_applications)
.setIcon(R.drawable.ic_menu_archive);
menu.add(0, DISPLAY_MODE_SHORTCUT, 0, R.string.quick_launch_display_mode_shortcuts)
.setIcon(R.drawable.ic_menu_goto);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(DISPLAY_MODE_LAUNCH).setVisible(mDisplayMode != DISPLAY_MODE_LAUNCH);
menu.findItem(DISPLAY_MODE_SHORTCUT).setVisible(mDisplayMode != DISPLAY_MODE_SHORTCUT);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case DISPLAY_MODE_LAUNCH:
mDisplayMode = DISPLAY_MODE_LAUNCH;
break;
case DISPLAY_MODE_SHORTCUT:
mDisplayMode = DISPLAY_MODE_SHORTCUT;
break;
default:
return false;
}
updateListAndAdapter();
return true;
}
private void ensureIntents() {
if (sLaunchIntent == null) {
sLaunchIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
sShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
}
}
/**
* This should be called from the UI thread.
*/
private void updateListAndAdapter() {
// Get the activities in a separate thread
new Thread("data updater") {
@Override
public void run() {
synchronized (BookmarkPicker.this) {
/*
* Don't touch any of the lists that are being used by the
* adapter in this thread!
*/
ArrayList<ResolveInfo> newResolveList = new ArrayList<ResolveInfo>();
ArrayList<Map<String, ?>> newAdapterList = new ArrayList<Map<String, ?>>();
fillResolveList(newResolveList);
Collections.sort(newResolveList,
new ResolveInfo.DisplayNameComparator(getPackageManager()));
fillAdapterList(newAdapterList, newResolveList);
updateAdapterToUseNewLists(newAdapterList, newResolveList);
}
}
}.start();
}
private void updateAdapterToUseNewLists(final ArrayList<Map<String, ?>> newAdapterList,
final ArrayList<ResolveInfo> newResolveList) {
// Post this back on the UI thread
mUiHandler.post(new Runnable() {
public void run() {
/*
* SimpleAdapter does not support changing the lists after it
* has been created. We just create a new instance.
*/
mMyAdapter = createResolveAdapter(newAdapterList);
mResolveList = newResolveList;
setListAdapter(mMyAdapter);
}
});
}
/**
* Gets all activities matching our current display mode.
*
* @param list The list to fill.
*/
private void fillResolveList(List<ResolveInfo> list) {
ensureIntents();
PackageManager pm = getPackageManager();
list.clear();
if (mDisplayMode == DISPLAY_MODE_LAUNCH) {
list.addAll(pm.queryIntentActivities(sLaunchIntent, 0));
} else if (mDisplayMode == DISPLAY_MODE_SHORTCUT) {
list.addAll(pm.queryIntentActivities(sShortcutIntent, 0));
}
}
private SimpleAdapter createResolveAdapter(List<Map<String, ?>> list) {
SimpleAdapter adapter = new SimpleAdapter(this, list,
R.layout.bookmark_picker_item, sKeys, sResourceIds);
adapter.setViewBinder(this);
return adapter;
}
private void fillAdapterList(List<Map<String, ?>> list,
List<ResolveInfo> resolveList) {
list.clear();
int resolveListSize = resolveList.size();
for (int i = 0; i < resolveListSize; i++) {
ResolveInfo info = resolveList.get(i);
/*
* Simple adapter craziness. For each item, we need to create a map
* from a key to its value (the value can be any object--the view
* binder will take care of filling the View with a representation
* of that object).
*/
Map<String, Object> map = new TreeMap<String, Object>();
map.put(KEY_TITLE, getResolveInfoTitle(info));
map.put(KEY_RESOLVE_INFO, info);
list.add(map);
}
}
/** Get the title for a resolve info. */
private String getResolveInfoTitle(ResolveInfo info) {
CharSequence label = info.loadLabel(getPackageManager());
if (label == null) label = info.activityInfo.name;
return label != null ? label.toString() : null;
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
if (position >= mResolveList.size()) return;
ResolveInfo info = mResolveList.get(position);
switch (mDisplayMode) {
case DISPLAY_MODE_LAUNCH:
// We can go ahead and return the clicked info's intent
Intent intent = getIntentForResolveInfo(info, Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
finish(intent, getResolveInfoTitle(info));
break;
case DISPLAY_MODE_SHORTCUT:
// Start the shortcut activity so the user can pick the actual intent
// (example: Gmail's shortcut activity shows a list of mailboxes)
startShortcutActivity(info);
break;
}
}
private static Intent getIntentForResolveInfo(ResolveInfo info, String action) {
Intent intent = new Intent(action);
ActivityInfo ai = info.activityInfo;
intent.setClassName(ai.packageName, ai.name);
return intent;
}
/**
* Starts an activity to get a shortcut.
* <p>
* For example, Gmail has an activity that lists the available labels. It
* returns a shortcut intent for going directly to this label.
*/
private void startShortcutActivity(ResolveInfo info) {
Intent intent = getIntentForResolveInfo(info, Intent.ACTION_CREATE_SHORTCUT);
startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
// Will get a callback to onActivityResult
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
switch (requestCode) {
case REQUEST_CREATE_SHORTCUT:
if (data != null) {
finish((Intent) data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT),
data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
/**
* Finishes the activity and returns the given data.
*/
private void finish(Intent intent, String title) {
// Give back what was given to us (it will have the shortcut, for example)
intent.putExtras(getIntent());
// Put our information
intent.putExtra(EXTRA_TITLE, title);
setResult(RESULT_OK, intent);
finish();
}
/**
* {@inheritDoc}
*/
public boolean setViewValue(View view, Object data, String textRepresentation) {
if (view.getId() == R.id.icon) {
Drawable icon = ((ResolveInfo) data).loadIcon(getPackageManager());
if (icon != null) {
((ImageView) view).setImageDrawable(icon);
}
return true;
} else {
return false;
}
}
}

View File

@@ -0,0 +1,347 @@
/*
* 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.quicklaunch;
import com.android.settings.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings.Bookmarks;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
/**
* Settings activity for quick launch.
* <p>
* Shows a list of possible shortcuts, the current application each is bound to,
* and allows choosing a new bookmark for a shortcut.
*/
public class QuickLaunchSettings extends PreferenceActivity implements
AdapterView.OnItemLongClickListener, DialogInterface.OnClickListener {
private static final String TAG = "QuickLaunchSettings";
private static final String KEY_SHORTCUT_CATEGORY = "shortcut_category";
private static final int DIALOG_CLEAR_SHORTCUT = 0;
private static final int REQUEST_PICK_BOOKMARK = 1;
private static final int COLUMN_SHORTCUT = 0;
private static final int COLUMN_TITLE = 1;
private static final String[] sProjection = new String[] {
Bookmarks.SHORTCUT, Bookmarks.TITLE
};
private static final String sShortcutSelection = Bookmarks.SHORTCUT + "=?";
private Handler mUiHandler = new Handler();
private static final String DEFAULT_BOOKMARK_FOLDER = "@default";
/** Cursor for Bookmarks provider. */
private Cursor mBookmarksCursor;
/** Listens for changes to Bookmarks provider. */
private BookmarksObserver mBookmarksObserver;
/** Used to keep track of which shortcuts have bookmarks. */
private SparseBooleanArray mBookmarkedShortcuts;
/** Preference category to hold the shortcut preferences. */
private PreferenceCategory mShortcutCategory;
/** Mapping of a shortcut to its preference. */
private SparseArray<ShortcutPreference> mShortcutToPreference;
/** The bookmark title of the shortcut that is being cleared. */
private CharSequence mClearDialogBookmarkTitle;
private static final String CLEAR_DIALOG_BOOKMARK_TITLE = "CLEAR_DIALOG_BOOKMARK_TITLE";
/** The shortcut that is being cleared. */
private char mClearDialogShortcut;
private static final String CLEAR_DIALOG_SHORTCUT = "CLEAR_DIALOG_SHORTCUT";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.quick_launch_settings);
mShortcutCategory = (PreferenceCategory) findPreference(KEY_SHORTCUT_CATEGORY);
mShortcutToPreference = new SparseArray<ShortcutPreference>();
mBookmarksObserver = new BookmarksObserver(mUiHandler);
initShortcutPreferences();
mBookmarksCursor = managedQuery(Bookmarks.CONTENT_URI, sProjection, null, null);
getListView().setOnItemLongClickListener(this);
}
@Override
protected void onResume() {
super.onResume();
getContentResolver().registerContentObserver(Bookmarks.CONTENT_URI, true,
mBookmarksObserver);
refreshShortcuts();
}
@Override
protected void onPause() {
super.onPause();
getContentResolver().unregisterContentObserver(mBookmarksObserver);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
// Restore the clear dialog's info
mClearDialogBookmarkTitle = state.getString(CLEAR_DIALOG_BOOKMARK_TITLE);
mClearDialogShortcut = (char) state.getInt(CLEAR_DIALOG_SHORTCUT, 0);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save the clear dialog's info
outState.putCharSequence(CLEAR_DIALOG_BOOKMARK_TITLE, mClearDialogBookmarkTitle);
outState.putInt(CLEAR_DIALOG_SHORTCUT, mClearDialogShortcut);
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_CLEAR_SHORTCUT: {
// Create the dialog for clearing a shortcut
return new AlertDialog.Builder(this)
.setTitle(getString(R.string.quick_launch_clear_dialog_title))
.setIcon(R.drawable.ic_dialog_alert)
.setMessage(getString(R.string.quick_launch_clear_dialog_message,
mClearDialogShortcut, mClearDialogBookmarkTitle))
.setPositiveButton(R.string.quick_launch_clear_ok_button, this)
.setNegativeButton(R.string.quick_launch_clear_cancel_button, this)
.create();
}
}
return super.onCreateDialog(id);
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch (id) {
case DIALOG_CLEAR_SHORTCUT: {
AlertDialog alertDialog = (AlertDialog) dialog;
alertDialog.setMessage(getString(R.string.quick_launch_clear_dialog_message,
mClearDialogShortcut, mClearDialogBookmarkTitle));
}
}
}
private void showClearDialog(ShortcutPreference pref) {
if (!pref.hasBookmark()) return;
mClearDialogBookmarkTitle = pref.getTitle();
mClearDialogShortcut = pref.getShortcut();
showDialog(DIALOG_CLEAR_SHORTCUT);
}
public void onClick(DialogInterface dialog, int which) {
if (mClearDialogShortcut > 0 && which == AlertDialog.BUTTON1) {
// Clear the shortcut
clearShortcut(mClearDialogShortcut);
}
mClearDialogBookmarkTitle = null;
mClearDialogShortcut = 0;
}
private void clearShortcut(char shortcut) {
getContentResolver().delete(Bookmarks.CONTENT_URI, sShortcutSelection,
new String[] { String.valueOf((int) shortcut) });
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (!(preference instanceof ShortcutPreference)) return false;
// Open the screen to pick a bookmark for this shortcut
ShortcutPreference pref = (ShortcutPreference) preference;
Intent intent = new Intent(this, BookmarkPicker.class);
intent.putExtra(BookmarkPicker.EXTRA_SHORTCUT, pref.getShortcut());
startActivityForResult(intent, REQUEST_PICK_BOOKMARK);
return true;
}
public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
// Open the clear shortcut dialog
Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(position);
if (!(pref instanceof ShortcutPreference)) return false;
showClearDialog((ShortcutPreference) pref);
return true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
if (requestCode == REQUEST_PICK_BOOKMARK) {
// Returned from the 'pick bookmark for this shortcut' screen
if (data == null) {
Log.w(TAG, "Result from bookmark picker does not have an intent.");
return;
}
String title = data.getStringExtra(BookmarkPicker.EXTRA_TITLE);
char shortcut = data.getCharExtra(BookmarkPicker.EXTRA_SHORTCUT, (char) 0);
updateShortcut(shortcut, title, data);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void updateShortcut(char shortcut, String title, Intent intent) {
// Update the bookmark for a shortcut
Bookmarks.add(getContentResolver(), intent, title.toString(), DEFAULT_BOOKMARK_FOLDER,
shortcut, 0);
}
private ShortcutPreference getOrCreatePreference(char shortcut) {
ShortcutPreference pref = mShortcutToPreference.get(shortcut);
if (pref != null) {
return pref;
} else {
Log.w(TAG, "Unknown shortcut '" + shortcut + "', creating preference anyway");
return createPreference(shortcut);
}
}
private ShortcutPreference createPreference(char shortcut) {
ShortcutPreference pref = new ShortcutPreference(QuickLaunchSettings.this, shortcut);
mShortcutCategory.addPreference(pref);
mShortcutToPreference.put(shortcut, pref);
return pref;
}
private void initShortcutPreferences() {
/** Whether the shortcut has been seen already. The array index is the shortcut. */
SparseBooleanArray shortcutSeen = new SparseBooleanArray();
KeyCharacterMap keyMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
// Go through all the key codes and create a preference for the appropriate keys
for (int keyCode = KeyEvent.MAX_KEYCODE - 1; keyCode >= 0; keyCode--) {
// Get the label for the primary char on the key that produces this key code
char shortcut = (char) Character.toLowerCase(keyMap.getDisplayLabel(keyCode));
if (shortcut == 0 || shortcutSeen.get(shortcut, false)) continue;
// TODO: need a to tell if the current keyboard can produce this key code, for now
// only allow the letter or digits
if (!Character.isLetterOrDigit(shortcut)) continue;
shortcutSeen.put(shortcut, true);
createPreference(shortcut);
}
}
private synchronized void refreshShortcuts() {
Cursor c = mBookmarksCursor;
if (c == null) {
// Haven't finished querying yet
return;
}
if (!c.requery()) {
Log.e(TAG, "Could not requery cursor when refreshing shortcuts.");
return;
}
/**
* We use the previous bookmarked shortcuts array to filter out those
* shortcuts that had bookmarks before this method call, and don't after
* (so we can set the preferences to be without bookmarks).
*/
SparseBooleanArray noLongerBookmarkedShortcuts = mBookmarkedShortcuts;
SparseBooleanArray newBookmarkedShortcuts = new SparseBooleanArray();
while (c.moveToNext()) {
char shortcut = Character.toLowerCase((char) c.getInt(COLUMN_SHORTCUT));
if (shortcut == 0) continue;
ShortcutPreference pref = getOrCreatePreference(shortcut);
pref.setTitle(c.getString(COLUMN_TITLE));
pref.setSummary(getString(R.string.quick_launch_shortcut,
String.valueOf(shortcut)));
pref.setHasBookmark(true);
newBookmarkedShortcuts.put(shortcut, true);
if (noLongerBookmarkedShortcuts != null) {
// After this loop, the shortcuts with value true in this array
// will no longer have bookmarks
noLongerBookmarkedShortcuts.put(shortcut, false);
}
}
if (noLongerBookmarkedShortcuts != null) {
for (int i = noLongerBookmarkedShortcuts.size() - 1; i >= 0; i--) {
if (noLongerBookmarkedShortcuts.valueAt(i)) {
// True, so there is no longer a bookmark for this shortcut
char shortcut = (char) noLongerBookmarkedShortcuts.keyAt(i);
ShortcutPreference pref = mShortcutToPreference.get(shortcut);
if (pref != null) {
pref.setHasBookmark(false);
}
}
}
}
mBookmarkedShortcuts = newBookmarkedShortcuts;
c.deactivate();
}
private class BookmarksObserver extends ContentObserver {
public BookmarksObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
refreshShortcuts();
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* 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.quicklaunch;
import com.android.settings.R;
import android.content.Context;
import android.content.res.ColorStateList;
import android.preference.Preference;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
/**
* Preference type for a shortcut in {@link QuickLaunchSettings}.
*/
public class ShortcutPreference extends Preference implements Comparable<Preference> {
private static Object sStaticVarsLock = new Object();
// These static fields are used across all instances of ShortcutPreference.
// There will be many ShortcutPreference instances (~36 for US).
private static String STRING_ASSIGN_APPLICATION;
private static String STRING_NO_SHORTCUT;
private static int sDimAlpha;
private static ColorStateList sRegularTitleColor;
private static ColorStateList sDimTitleColor;
private static ColorStateList sRegularSummaryColor;
private static ColorStateList sDimSummaryColor;
private char mShortcut;
private boolean mHasBookmark;
public ShortcutPreference(Context context, char shortcut) {
super(context);
synchronized (sStaticVarsLock) {
// Init statics. This should only happen for the first ShortcutPreference created,
// the rest will already have them initialized.
if (STRING_ASSIGN_APPLICATION == null) {
STRING_ASSIGN_APPLICATION = context.getString(R.string.quick_launch_assign_application);
STRING_NO_SHORTCUT = context.getString(R.string.quick_launch_no_shortcut);
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
sDimAlpha = (int) (outValue.getFloat() * 255);
}
}
mShortcut = shortcut;
setWidgetLayoutResource(R.layout.preference_widget_shortcut);
}
public char getShortcut() {
return mShortcut;
}
public void setShortcut(char shortcut) {
if (shortcut != mShortcut) {
mShortcut = shortcut;
notifyChanged();
}
}
public boolean hasBookmark() {
return mHasBookmark;
}
public void setHasBookmark(boolean hasBookmark) {
if (hasBookmark != mHasBookmark) {
mHasBookmark = hasBookmark;
notifyChanged();
}
}
@Override
public CharSequence getTitle() {
return mHasBookmark ? super.getTitle() : STRING_ASSIGN_APPLICATION;
}
@Override
public CharSequence getSummary() {
return mHasBookmark ? super.getSummary() : STRING_NO_SHORTCUT;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
TextView shortcutView = (TextView) view.findViewById(R.id.shortcut);
if (shortcutView != null) {
shortcutView.setText(String.valueOf(mShortcut));
}
TextView titleView = (TextView) view.findViewById(android.R.id.title);
synchronized (sStaticVarsLock) {
if (sRegularTitleColor == null) {
sRegularTitleColor = titleView.getTextColors();
sDimTitleColor = sRegularTitleColor.withAlpha(sDimAlpha);
}
}
ColorStateList color = mHasBookmark ? sRegularTitleColor : sDimTitleColor;
if (color != null) {
titleView.setTextColor(color);
}
TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
synchronized (sStaticVarsLock) {
if (sRegularSummaryColor == null) {
sRegularSummaryColor = summaryView.getTextColors();
sDimSummaryColor = sRegularSummaryColor.withAlpha(sDimAlpha);
}
}
color = mHasBookmark ? sRegularSummaryColor : sDimSummaryColor;
if (color != null) {
summaryView.setTextColor(color);
}
}
public int compareTo(Preference another) {
if (!(another instanceof ShortcutPreference)) return super.compareTo(another);
// Letters before digits
char other = ((ShortcutPreference) another).mShortcut;
if (Character.isDigit(mShortcut) && Character.isLetter(other)) return 1;
else if (Character.isDigit(other) && Character.isLetter(mShortcut)) return -1;
else return mShortcut - other;
}
}

View File

@@ -0,0 +1,607 @@
/*
* 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.wifi;
import com.android.settings.R;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.method.PasswordTransformationMethod;
import android.text.method.TransformationMethod;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TableLayout;
import android.widget.TextView;
public class AccessPointDialog extends AlertDialog implements DialogInterface.OnClickListener,
AdapterView.OnItemSelectedListener, View.OnClickListener {
private static final String TAG = "AccessPointDialog";
private static final String INSTANCE_KEY_ACCESS_POINT_STATE =
"com.android.settings.wifi.AccessPointDialog:accessPointState";
private static final String INSTANCE_KEY_MODE =
"com.android.settings.wifi.AccessPointDialog:mode";
private static final String INSTANCE_KEY_CUSTOM_TITLE =
"com.android.settings.wifi.AccessPointDialog:customTitle";
private static final String INSTANCE_KEY_AUTO_SECURITY_ALLOWED =
"com.android.settings.wifi.AccessPointDialog:autoSecurityAllowed";
private static final int POSITIVE_BUTTON = BUTTON1;
private static final int NEGATIVE_BUTTON = BUTTON2;
private static final int NEUTRAL_BUTTON = BUTTON3;
/** The dialog should show info connectivity functionality */
public static final int MODE_INFO = 0;
/** The dialog should configure the detailed AP properties */
public static final int MODE_CONFIGURE = 1;
/** The dialog should have the password field and connect/cancel */
public static final int MODE_RETRY_PASSWORD = 2;
// These should be matched with the XML. Both arrays in XML depend on this
// ordering!
private static final int SECURITY_AUTO = 0;
private static final int SECURITY_NONE = 1;
private static final int SECURITY_WEP = 2;
private static final int SECURITY_WPA_PERSONAL = 3;
private static final int SECURITY_WPA2_PERSONAL = 4;
private static final int[] WEP_TYPE_VALUES = {
AccessPointState.WEP_PASSWORD_AUTO, AccessPointState.WEP_PASSWORD_ASCII,
AccessPointState.WEP_PASSWORD_HEX
};
// Button positions, default to impossible values
private int mConnectButtonPos = Integer.MAX_VALUE;
private int mForgetButtonPos = Integer.MAX_VALUE;
private int mSaveButtonPos = Integer.MAX_VALUE;
// Client configurable items. Generally, these should be saved in instance state
private int mMode = MODE_INFO;
private boolean mAutoSecurityAllowed = true;
private CharSequence mCustomTitle;
// This does not need to be saved in instance state.
private WifiLayer mWifiLayer;
private AccessPointState mState;
// General views
private View mView;
private TextView mPasswordText;
private EditText mPasswordEdit;
private CheckBox mShowPasswordCheckBox;
// Info-specific views
private ViewGroup mTable;
// Configure-specific views
private EditText mSsidEdit;
private Spinner mSecuritySpinner;
private Spinner mWepTypeSpinner;
public AccessPointDialog(Context context, WifiLayer wifiLayer) {
super(context);
mWifiLayer = wifiLayer;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
onLayout();
onFill();
super.onCreate(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Set to a class loader that can find AccessPointState
savedInstanceState.setClassLoader(getClass().getClassLoader());
mState = savedInstanceState.getParcelable(INSTANCE_KEY_ACCESS_POINT_STATE);
mState.setContext(getContext());
mMode = savedInstanceState.getInt(INSTANCE_KEY_MODE, mMode);
mAutoSecurityAllowed = savedInstanceState.getBoolean(INSTANCE_KEY_AUTO_SECURITY_ALLOWED,
mAutoSecurityAllowed);
mCustomTitle = savedInstanceState.getCharSequence(INSTANCE_KEY_CUSTOM_TITLE);
if (mCustomTitle != null) {
setTitle(mCustomTitle);
}
// This is called last since it depends on the above values
super.onRestoreInstanceState(savedInstanceState);
if (mShowPasswordCheckBox != null) {
// Restore the show-password-state on the edit text
setShowPassword(mShowPasswordCheckBox.isChecked());
}
}
@Override
public Bundle onSaveInstanceState() {
Bundle bundle = super.onSaveInstanceState();
bundle.putParcelable(INSTANCE_KEY_ACCESS_POINT_STATE, mState);
bundle.putInt(INSTANCE_KEY_MODE, mMode);
bundle.putBoolean(INSTANCE_KEY_AUTO_SECURITY_ALLOWED, mAutoSecurityAllowed);
bundle.putCharSequence(INSTANCE_KEY_CUSTOM_TITLE, mCustomTitle);
return bundle;
}
/**
* Sets state to show in this dialog.
*
* @param state The state.
*/
public void setState(AccessPointState state) {
mState = state;
}
/**
* Sets the dialog mode.
* @param mode One of {@link #MODE_CONFIGURE} or {@link #MODE_INFO}
*/
public void setMode(int mode) {
mMode = mode;
}
public void setAutoSecurityAllowed(boolean autoSecurityAllowed) {
mAutoSecurityAllowed = autoSecurityAllowed;
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mCustomTitle = title;
}
@Override
public void setTitle(int titleId) {
setTitle(getContext().getString(titleId));
}
/** Called after flags are set, the dialog's layout/etc should be set up here */
private void onLayout() {
final Context context = getContext();
final String ssid = mState.getHumanReadableSsid();
int positiveButtonResId = 0;
int negativeButtonResId = R.string.cancel;
int neutralButtonResId = 0;
if (mCustomTitle == null) {
// Generic title is the SSID
// We don't want to trigger this as a custom title, so call super's
super.setTitle(ssid);
}
setInverseBackgroundForced(true);
boolean defaultPasswordVisibility = true;
if (mMode == MODE_CONFIGURE) {
setLayout(R.layout.wifi_ap_configure);
positiveButtonResId = R.string.wifi_save_config;
mSaveButtonPos = POSITIVE_BUTTON;
} else if (mMode == MODE_INFO) {
setLayout(R.layout.wifi_ap_info);
if (mState.isConnectable()) {
if (mCustomTitle == null) {
// We don't want to trigger this as a custom title, so call super's
super.setTitle(context.getString(R.string.connect_to_blank, ssid));
}
positiveButtonResId = R.string.connect;
mConnectButtonPos = POSITIVE_BUTTON;
}
if (mState.isForgetable()) {
if (positiveButtonResId == 0) {
positiveButtonResId = R.string.forget_network;
mForgetButtonPos = POSITIVE_BUTTON;
} else {
neutralButtonResId = R.string.forget_network;
mForgetButtonPos = NEUTRAL_BUTTON;
}
}
} else if (mMode == MODE_RETRY_PASSWORD) {
setLayout(R.layout.wifi_ap_retry_password);
positiveButtonResId = R.string.connect;
mConnectButtonPos = POSITIVE_BUTTON;
setGenericPasswordVisible(true);
defaultPasswordVisibility = false;
}
if (defaultPasswordVisibility) {
if (!mState.configured && mState.seen && mState.hasSecurity()) {
setGenericPasswordVisible(true);
} else {
setGenericPasswordVisible(false);
}
}
setButtons(positiveButtonResId, negativeButtonResId, neutralButtonResId);
}
/** Called when we need to set our member variables to point to the views. */
private void onReferenceViews(View view) {
mPasswordText = (TextView) view.findViewById(R.id.password_text);
mPasswordEdit = (EditText) view.findViewById(R.id.password_edit);
mShowPasswordCheckBox = (CheckBox) view.findViewById(R.id.show_password_checkbox);
if (mShowPasswordCheckBox != null) {
mShowPasswordCheckBox.setOnClickListener(this);
}
if (mMode == MODE_CONFIGURE) {
mSsidEdit = (EditText) view.findViewById(R.id.ssid_edit);
mSecuritySpinner = (Spinner) view.findViewById(R.id.security_spinner);
mSecuritySpinner.setOnItemSelectedListener(this);
setSecuritySpinnerAdapter();
mWepTypeSpinner = (Spinner) view.findViewById(R.id.wep_type_spinner);
} else if (mMode == MODE_INFO) {
mTable = (ViewGroup) view.findViewById(R.id.table);
}
}
private void setSecuritySpinnerAdapter() {
Context context = getContext();
int arrayResId = mAutoSecurityAllowed ? R.array.wifi_security_entries
: R.array.wifi_security_without_auto_entries;
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context,
android.R.layout.simple_spinner_item,
context.getResources().getStringArray(arrayResId));
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSecuritySpinner.setAdapter(adapter);
}
/** Called when the widgets are in-place waiting to be filled with data */
private void onFill() {
// Appears in the order added
if (mMode == MODE_INFO) {
if (mState.primary) {
addInfoRow(R.string.wifi_status, mState.getSummarizedStatus());
addInfoRow(R.string.wifi_link_speed, mState.linkSpeed + WifiInfo.LINK_SPEED_UNITS);
}
if (mState.seen) {
addInfoRow(R.string.signal, getSignalResId(mState.signal));
}
if (mState.security != null) {
addInfoRow(R.string.security, mState.getHumanReadableSecurity());
}
if (mState.primary && mState.ipAddress != 0) {
addInfoRow(R.string.ip_address, ipAddressToString(mState.ipAddress));
}
} else if (mMode == MODE_CONFIGURE) {
String ssid = mState.getHumanReadableSsid();
if (!TextUtils.isEmpty(ssid)) {
mSsidEdit.setText(ssid);
}
mPasswordEdit.setHint(R.string.wifi_password_unchanged);
}
updatePasswordCaption(mState.security);
}
private void updatePasswordCaption(String security) {
if (mPasswordText != null && security != null
&& security.equals(AccessPointState.WEP)) {
mPasswordText.setText(R.string.please_type_hex_key);
} else {
mPasswordText.setText(R.string.please_type_passphrase);
}
}
private void addInfoRow(int nameResId, String value) {
View rowView = getLayoutInflater().inflate(R.layout.wifi_ap_info_row, mTable, false);
((TextView) rowView.findViewById(R.id.name)).setText(nameResId);
((TextView) rowView.findViewById(R.id.value)).setText(value);
mTable.addView(rowView);
}
private void addInfoRow(int nameResId, int valueResId) {
addInfoRow(nameResId, getContext().getString(valueResId));
}
private void setButtons(int positiveResId, int negativeResId, int neutralResId) {
final Context context = getContext();
if (positiveResId > 0) {
setButton(context.getString(positiveResId), this);
}
if (negativeResId > 0) {
setButton2(context.getString(negativeResId), this);
}
if (neutralResId > 0) {
setButton3(context.getString(neutralResId), this);
}
}
private void setLayout(int layoutResId) {
setView(mView = getLayoutInflater().inflate(layoutResId, null));
onReferenceViews(mView);
}
public void onClick(DialogInterface dialog, int which) {
if (which == mForgetButtonPos) {
handleForget();
} else if (which == mConnectButtonPos) {
handleConnect();
} else if (which == mSaveButtonPos) {
handleSave();
}
}
private void handleForget() {
if (!replaceStateWithWifiLayerInstance()) return;
mWifiLayer.forgetNetwork(mState);
}
private void handleConnect() {
if (!replaceStateWithWifiLayerInstance()) {
Log.w(TAG, "Assuming connecting to a new network.");
}
/*
* If the network is secured and they haven't entered a password, popup
* an error. Allow empty passwords if the state already has a password
* set (since in that scenario, an empty password means keep the old
* password).
*/
String password = getEnteredPassword();
boolean passwordIsEmpty = TextUtils.isEmpty(password);
/*
* When 'retry password', they can not enter a blank password. In any
* other mode, we let them enter a blank password if the state already
* has a password.
*/
if (passwordIsEmpty && (!mState.hasPassword() || mMode == MODE_RETRY_PASSWORD)
&& (mState.security != null) && !mState.security.equals(AccessPointState.OPEN)) {
new AlertDialog.Builder(getContext())
.setTitle(R.string.error_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.wifi_password_incorrect_error)
.setPositiveButton(android.R.string.ok, null)
.show();
return;
}
if (!passwordIsEmpty) {
mState.setPassword(password);
}
mWifiLayer.connectToNetwork(mState);
}
private void handleSave() {
replaceStateWithWifiLayerInstance();
String ssid = mSsidEdit.getText().toString();
String password = mPasswordEdit.getText().toString();
mState.setSsid(ssid);
int securityType = getSecurityTypeFromSpinner();
if (!TextUtils.isEmpty(password)) {
switch (securityType) {
case SECURITY_WPA_PERSONAL: {
mState.setSecurity(AccessPointState.WPA);
mState.setPassword(password);
break;
}
case SECURITY_WPA2_PERSONAL: {
mState.setSecurity(AccessPointState.WPA2);
mState.setPassword(password);
break;
}
case SECURITY_AUTO: {
mState.setPassword(password);
break;
}
case SECURITY_WEP: {
mState.setSecurity(AccessPointState.WEP);
mState.setPassword(password,
WEP_TYPE_VALUES[mWepTypeSpinner.getSelectedItemPosition()]);
break;
}
}
} else {
mState.setSecurity(AccessPointState.OPEN);
}
if (securityType == SECURITY_NONE) {
mState.setSecurity(AccessPointState.OPEN);
}
if (!mWifiLayer.saveNetwork(mState)) {
return;
}
// Connect right away if they've touched it
if (!mWifiLayer.connectToNetwork(mState)) {
return;
}
}
/**
* Replaces our {@link #mState} with the equal WifiLayer instance. This is useful after
* we unparceled the state previously and before we are calling methods on {@link #mWifiLayer}.
*
* @return Whether WifiLayer was able to find an equal state in its set.
*/
private boolean replaceStateWithWifiLayerInstance() {
AccessPointState state = mWifiLayer.getWifiLayerApInstance(mState);
if (state == null) {
return false;
}
mState = state;
return true;
}
private int getSecurityTypeFromSpinner() {
int position = mSecuritySpinner.getSelectedItemPosition();
// If there is no AUTO choice, the position needs 1 added to get
// to the proper spinner position -> security constants mapping
return mAutoSecurityAllowed ? position : position + 1;
}
private String getEnteredPassword() {
return mPasswordEdit != null ? mPasswordEdit.getText().toString() : null;
}
/**
* Call the one you want to hide first.
*/
private void setWepVisible(boolean visible) {
setGenericPasswordVisible(visible);
int visibility = visible ? View.VISIBLE : View.GONE;
mWepTypeSpinner.setVisibility(visibility);
}
/**
* @see #setWepVisible(boolean)
*/
private void setGenericPasswordVisible(boolean visible) {
int visibility = visible ? View.VISIBLE : View.GONE;
mPasswordText.setVisibility(visibility);
mPasswordEdit.setVisibility(visibility);
mShowPasswordCheckBox.setVisibility(visibility);
}
public void onItemSelected(AdapterView parent, View view, int position, long id) {
if (parent == mSecuritySpinner) {
handleSecurityChange(getSecurityTypeFromSpinner());
}
}
public void onNothingSelected(AdapterView parent) {
}
private void handleSecurityChange(int security) {
switch (security) {
case SECURITY_NONE: {
setWepVisible(false);
setGenericPasswordVisible(false);
break;
}
case SECURITY_WEP: {
setGenericPasswordVisible(false);
setWepVisible(true);
updatePasswordCaption(AccessPointState.WEP);
break;
}
case SECURITY_AUTO: {
setWepVisible(false);
setGenericPasswordVisible(mState.hasSecurity());
// Shows the generic 'wireless password'
updatePasswordCaption(AccessPointState.WPA);
break;
}
case SECURITY_WPA_PERSONAL:
case SECURITY_WPA2_PERSONAL: {
setWepVisible(false);
setGenericPasswordVisible(true);
// Both WPA and WPA2 show the same caption, so either is ok
updatePasswordCaption(AccessPointState.WPA);
break;
}
}
}
private static int getSignalResId(int signal) {
switch (WifiManager.calculateSignalLevel(signal, 4)) {
case 0: {
return R.string.wifi_signal_0;
}
case 1: {
return R.string.wifi_signal_1;
}
case 2: {
return R.string.wifi_signal_2;
}
case 3: {
return R.string.wifi_signal_3;
}
}
return 0;
}
private static String ipAddressToString(int addr) {
StringBuffer buf = new StringBuffer();
buf.append(addr & 0xff).append('.').
append((addr >>>= 8) & 0xff).append('.').
append((addr >>>= 8) & 0xff).append('.').
append((addr >>>= 8) & 0xff);
return buf.toString();
}
public void onClick(View v) {
if (v == mShowPasswordCheckBox) {
setShowPassword(mShowPasswordCheckBox.isChecked());
}
}
private void setShowPassword(boolean showPassword) {
if (mPasswordEdit != null) {
// Toggle password
mPasswordEdit.setTransformationMethod(
showPassword ?
null :
PasswordTransformationMethod.getInstance());
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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.wifi;
import com.android.settings.R;
import android.net.wifi.WifiManager;
import android.preference.Preference;
import android.view.View;
import android.widget.ImageView;
public class AccessPointPreference extends Preference implements
AccessPointState.AccessPointStateCallback {
// UI states
private static final int[] STATE_ENCRYPTED = { R.attr.state_encrypted };
private static final int[] STATE_EMPTY = { };
// Signal strength indicator
private static final int UI_SIGNAL_LEVELS = 4;
private WifiSettings mWifiSettings;
private AccessPointState mState;
public AccessPointPreference(WifiSettings wifiSettings, AccessPointState state) {
super(wifiSettings, null);
mWifiSettings = wifiSettings;
mState = state;
setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
state.setCallback(this);
refresh();
}
public void refresh() {
setTitle(mState.getHumanReadableSsid());
setSummary(mState.getSummarizedStatus());
notifyChanged();
}
public void refreshAccessPointState() {
refresh();
// The ordering of access points could have changed due to the state change, so
// re-evaluate ordering
notifyHierarchyChanged();
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView signal = (ImageView) view.findViewById(R.id.signal);
if (mState.seen) {
signal.setImageResource(R.drawable.wifi_signal);
signal.setImageState(mState.hasSecurity() ? STATE_ENCRYPTED : STATE_EMPTY, true);
signal.setImageLevel(getUiSignalLevel());
} else {
signal.setImageDrawable(null);
}
}
private int getUiSignalLevel() {
return mState != null ? WifiManager.calculateSignalLevel(mState.signal, UI_SIGNAL_LEVELS)
: 0;
}
/**
* Returns the {@link AccessPointState} associated with this preference.
* @return The {@link AccessPointState}.
*/
public AccessPointState getAccessPointState() {
return mState;
}
@Override
public int compareTo(Preference another) {
if (!(another instanceof AccessPointPreference)) {
// Let normal preferences go before us.
// NOTE: we should only be compared to Preference in our
// category.
return 1;
}
return mState.compareTo(((AccessPointPreference) another).mState);
}
}

View File

@@ -0,0 +1,869 @@
/*
* 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.wifi;
import com.android.settings.R;
import android.content.Context;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.GroupCipher;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.PairwiseCipher;
import android.net.wifi.WifiConfiguration.Protocol;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
public final class AccessPointState implements Comparable<AccessPointState>, Parcelable {
private static final String TAG = "AccessPointState";
// Constants used for different security types
public static final String WPA2 = "WPA2";
public static final String WPA = "WPA";
public static final String WEP = "WEP";
public static final String OPEN = "Open";
/** String present in capabilities if the scan result is ad-hoc */
private static final String ADHOC_CAPABILITY = "[IBSS]";
/** String present in capabilities if the scan result is enterprise secured */
private static final String ENTERPRISE_CAPABILITY = "-EAP-";
// Localized strings for different security types
private static String LOCALIZED_WPA2;
private static String LOCALIZED_WPA;
private static String LOCALIZED_WEP;
private static String LOCALIZED_OPEN;
private static String LOCALIZED_UNKNOWN;
private static String LOCALIZED_VERBOSE_WPA2;
private static String LOCALIZED_VERBOSE_WPA;
private static String LOCALIZED_VERBOSE_WEP;
private static String LOCALIZED_VERBOSE_OPEN;
// Localized strings for various messages
private static String SUMMARY_NOT_IN_RANGE;
private static String SUMMARY_REMEMBERED;
private static String SUMMARY_CONNECTION_FAILED;
public static final String BSSID_ANY = "any";
public static final int NETWORK_ID_NOT_SET = -1;
/** This should be used with care! */
static final int NETWORK_ID_ANY = -2;
public static final int MATCH_NONE = 0;
public static final int MATCH_WEAK = 1;
public static final int MATCH_STRONG = 2;
public static final int MATCH_EXACT = 3;
// Don't set these directly, use the setters.
public int networkId;
public int priority;
public boolean hiddenSsid;
public int linkSpeed;
public int ipAddress;
public String bssid;
public String ssid;
public int signal;
public boolean primary;
public boolean seen;
public boolean configured;
public NetworkInfo.DetailedState status;
public String security;
public boolean disabled;
/**
* Use this for sorting based on signal strength. It is a heavily-damped
* time-averaged weighted signal.
*/
private float signalForSorting = Float.MIN_VALUE;
private static final float DAMPING_FACTOR = 0.2f;
/**
* This will be a user entered password, and NOT taken from wpa_supplicant
* (since it would give us *)
*/
private String mPassword;
private boolean mConfigHadPassword;
public static final int WEP_PASSWORD_AUTO = 0;
public static final int WEP_PASSWORD_ASCII = 1;
public static final int WEP_PASSWORD_HEX = 2;
private int mWepPasswordType;
private Context mContext;
/**
* If > 0, don't refresh (changes are being batched), use
* {@link #blockRefresh()} and {@link #unblockRefresh()} only.
*/
private int mBlockRefresh;
/**
* This will be set by {@link #requestRefresh} and shouldn't be written to
* elsewhere.
*/
private boolean mNeedsRefresh;
private AccessPointStateCallback mCallback;
private StringBuilder mSummaryBuilder = new StringBuilder();
interface AccessPointStateCallback {
void refreshAccessPointState();
}
public AccessPointState(Context context) {
this();
setContext(context);
}
private AccessPointState() {
bssid = BSSID_ANY;
ssid = "";
networkId = NETWORK_ID_NOT_SET;
hiddenSsid = false;
}
void setContext(Context context) {
mContext = context;
setStrings();
}
private void setStrings() {
final Context c = mContext;
if (SUMMARY_NOT_IN_RANGE == null && c != null) {
SUMMARY_NOT_IN_RANGE = c.getString(R.string.summary_not_in_range);
SUMMARY_REMEMBERED = c.getString(R.string.summary_remembered);
SUMMARY_CONNECTION_FAILED = c.getString(R.string.summary_connection_failed);
LOCALIZED_OPEN = c.getString(R.string.wifi_security_open);
LOCALIZED_WEP = c.getString(R.string.wifi_security_wep);
LOCALIZED_WPA = c.getString(R.string.wifi_security_wpa);
LOCALIZED_WPA2 = c.getString(R.string.wifi_security_wpa2);
LOCALIZED_VERBOSE_OPEN = c.getString(R.string.wifi_security_verbose_open);
LOCALIZED_VERBOSE_WEP = c.getString(R.string.wifi_security_verbose_wep);
LOCALIZED_VERBOSE_WPA = c.getString(R.string.wifi_security_verbose_wpa);
LOCALIZED_VERBOSE_WPA2 = c.getString(R.string.wifi_security_verbose_wpa2);
LOCALIZED_UNKNOWN = c.getString(R.string.wifi_security_unknown);
}
}
public void setNetworkId(int networkId) {
this.networkId = networkId;
}
public void setBssid(String bssid) {
if (bssid != null) {
// If the BSSID is a wildcard, do NOT let a specific BSSID replace it
if (!this.bssid.equals(BSSID_ANY)) {
this.bssid = bssid;
}
}
}
private String getWpaSupplicantBssid() {
return bssid.equals(BSSID_ANY) ? null : bssid;
}
public static String convertToQuotedString(String string) {
if (TextUtils.isEmpty(string)) {
return "";
}
final int lastPos = string.length() - 1;
if (lastPos < 0 || (string.charAt(0) == '"' && string.charAt(lastPos) == '"')) {
return string;
}
return "\"" + string + "\"";
}
public void setPrimary(boolean primary) {
if (this.primary != primary) {
this.primary = primary;
requestRefresh();
}
}
public void setSeen(boolean seen) {
if (this.seen != seen) {
this.seen = seen;
requestRefresh();
}
}
public void setDisabled(boolean disabled) {
if (this.disabled != disabled) {
this.disabled = disabled;
requestRefresh();
}
}
public void setSignal(int signal) {
if (signalForSorting == Float.MIN_VALUE) {
signalForSorting = signal;
} else {
signalForSorting = (DAMPING_FACTOR * signal) + ((1-DAMPING_FACTOR) * signalForSorting);
}
if (this.signal != signal) {
this.signal = signal;
requestRefresh();
}
}
public String getHumanReadableSsid() {
if (TextUtils.isEmpty(ssid)) {
return "";
}
final int lastPos = ssid.length() - 1;
if (ssid.charAt(0) == '"' && ssid.charAt(lastPos) == '"') {
return ssid.substring(1, lastPos);
}
return ssid;
}
public void setSsid(String ssid) {
if (ssid != null) {
this.ssid = convertToQuotedString(ssid);
requestRefresh();
}
}
public void setPriority(int priority) {
if (this.priority != priority) {
this.priority = priority;
requestRefresh();
}
}
public void setHiddenSsid(boolean hiddenSsid) {
if (this.hiddenSsid != hiddenSsid) {
this.hiddenSsid = hiddenSsid;
requestRefresh();
}
}
public void setLinkSpeed(int linkSpeed) {
if (this.linkSpeed != linkSpeed) {
this.linkSpeed = linkSpeed;
requestRefresh();
}
}
public void setIpAddress(int address) {
if (ipAddress != address) {
ipAddress = address;
requestRefresh();
}
}
public void setConfigured(boolean configured) {
if (this.configured != configured) {
this.configured = configured;
requestRefresh();
}
}
public void setStatus(NetworkInfo.DetailedState status) {
if (this.status != status) {
this.status = status;
requestRefresh();
}
}
public void setSecurity(String security) {
if (TextUtils.isEmpty(this.security) || !this.security.equals(security)) {
this.security = security;
requestRefresh();
}
}
public boolean hasSecurity() {
return security != null && !security.contains(OPEN);
}
public String getHumanReadableSecurity() {
if (security.equals(OPEN)) return LOCALIZED_OPEN;
else if (security.equals(WEP)) return LOCALIZED_WEP;
else if (security.equals(WPA)) return LOCALIZED_WPA;
else if (security.equals(WPA2)) return LOCALIZED_WPA2;
return LOCALIZED_UNKNOWN;
}
public void updateFromScanResult(ScanResult scanResult) {
blockRefresh();
// We don't keep specific AP BSSIDs and instead leave that as wildcard
setSeen(true);
setSsid(scanResult.SSID);
if (networkId == NETWORK_ID_NOT_SET) {
// Since ScanResults don't cross-reference network ID, we set it as a wildcard
setNetworkId(NETWORK_ID_ANY);
}
setSignal(scanResult.level);
setSecurity(getScanResultSecurity(scanResult));
unblockRefresh();
}
/**
* @return The security of a given {@link ScanResult}.
*/
public static String getScanResultSecurity(ScanResult scanResult) {
final String cap = scanResult.capabilities;
final String[] securityModes = { WEP, WPA, WPA2 };
for (int i = securityModes.length - 1; i >= 0; i--) {
if (cap.contains(securityModes[i])) {
return securityModes[i];
}
}
return OPEN;
}
/**
* @return Whether the given ScanResult represents an adhoc network.
*/
public static boolean isAdhoc(ScanResult scanResult) {
return scanResult.capabilities.contains(ADHOC_CAPABILITY);
}
/**
* @return Whether the given ScanResult has enterprise security.
*/
public static boolean isEnterprise(ScanResult scanResult) {
return scanResult.capabilities.contains(ENTERPRISE_CAPABILITY);
}
public void updateFromWifiConfiguration(WifiConfiguration wifiConfig) {
if (wifiConfig != null) {
blockRefresh();
setBssid(wifiConfig.BSSID);
setNetworkId(wifiConfig.networkId);
setPriority(wifiConfig.priority);
setHiddenSsid(wifiConfig.hiddenSSID);
setSsid(wifiConfig.SSID);
setConfigured(true);
setDisabled(wifiConfig.status == WifiConfiguration.Status.DISABLED);
parseWifiConfigurationSecurity(wifiConfig);
unblockRefresh();
}
}
public void setPassword(String password) {
setPassword(password, WEP_PASSWORD_AUTO);
}
public void setPassword(String password, int wepPasswordType) {
mPassword = password;
mWepPasswordType = wepPasswordType;
}
public boolean hasPassword() {
return !TextUtils.isEmpty(mPassword) || mConfigHadPassword;
}
private static boolean hasPassword(WifiConfiguration wifiConfig) {
return !TextUtils.isEmpty(wifiConfig.preSharedKey)
|| !TextUtils.isEmpty(wifiConfig.wepKeys[0])
|| !TextUtils.isEmpty(wifiConfig.wepKeys[1])
|| !TextUtils.isEmpty(wifiConfig.wepKeys[2])
|| !TextUtils.isEmpty(wifiConfig.wepKeys[3]);
}
private void parseWifiConfigurationSecurity(WifiConfiguration wifiConfig) {
setSecurity(getWifiConfigurationSecurity(wifiConfig));
mConfigHadPassword = hasPassword(wifiConfig);
}
/**
* @return The security of a given {@link WifiConfiguration}.
*/
public static String getWifiConfigurationSecurity(WifiConfiguration wifiConfig) {
if (wifiConfig.allowedKeyManagement.get(KeyMgmt.NONE)) {
// If we never set group ciphers, wpa_supplicant puts all of them.
// For open, we don't set group ciphers.
// For WEP, we specifically only set WEP40 and WEP104, so CCMP
// and TKIP should not be there.
if (!wifiConfig.allowedGroupCiphers.get(GroupCipher.CCMP)
&& (wifiConfig.allowedGroupCiphers.get(GroupCipher.WEP40)
|| wifiConfig.allowedGroupCiphers.get(GroupCipher.WEP104))) {
return WEP;
} else {
return OPEN;
}
} else if (wifiConfig.allowedProtocols.get(Protocol.RSN)) {
return WPA2;
} else if (wifiConfig.allowedProtocols.get(Protocol.WPA)) {
return WPA;
} else {
Log.w(TAG, "Unknown security type from WifiConfiguration, falling back on open.");
return OPEN;
}
}
public void updateFromWifiInfo(WifiInfo wifiInfo, NetworkInfo.DetailedState state) {
if (wifiInfo != null) {
blockRefresh();
setBssid(wifiInfo.getBSSID());
setLinkSpeed(wifiInfo.getLinkSpeed());
setNetworkId(wifiInfo.getNetworkId());
setIpAddress(wifiInfo.getIpAddress());
setSsid(wifiInfo.getSSID());
if (state != null) {
setStatus(state);
}
setHiddenSsid(wifiInfo.getHiddenSSID());
unblockRefresh();
}
}
/**
* @return Whether this AP can be connected to at the moment.
*/
public boolean isConnectable() {
return !primary && seen;
}
/**
* @return Whether this AP can be forgotten at the moment.
*/
public boolean isForgetable() {
return configured;
}
/**
* Updates the state as if it were never configured.
* <p>
* Note: This will not pass the forget call to the Wi-Fi API.
*/
public void forget() {
blockRefresh();
setConfigured(false);
setNetworkId(NETWORK_ID_NOT_SET);
setPrimary(false);
setStatus(null);
setDisabled(false);
unblockRefresh();
}
public void updateWifiConfiguration(WifiConfiguration config) {
config.BSSID = getWpaSupplicantBssid();
config.priority = priority;
config.hiddenSSID = hiddenSsid;
config.SSID = convertToQuotedString(ssid);
setupSecurity(config);
}
private void setupSecurity(WifiConfiguration config) {
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
if (TextUtils.isEmpty(security)) {
security = OPEN;
Log.w(TAG, "Empty security, assuming open");
}
if (security.equals(WEP)) {
// If password is empty, it should be left untouched
if (!TextUtils.isEmpty(mPassword)) {
if (mWepPasswordType == WEP_PASSWORD_AUTO) {
if (isHexWepKey(mPassword)) {
config.wepKeys[0] = mPassword;
} else {
config.wepKeys[0] = convertToQuotedString(mPassword);
}
} else {
config.wepKeys[0] = mWepPasswordType == WEP_PASSWORD_ASCII
? convertToQuotedString(mPassword)
: mPassword;
}
}
config.wepTxKeyIndex = 0;
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
config.allowedKeyManagement.set(KeyMgmt.NONE);
config.allowedGroupCiphers.set(GroupCipher.WEP40);
config.allowedGroupCiphers.set(GroupCipher.WEP104);
} else if (security.equals(WPA) || security.equals(WPA2)){
config.allowedGroupCiphers.set(GroupCipher.TKIP);
config.allowedGroupCiphers.set(GroupCipher.CCMP);
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
config.allowedProtocols.set(security.equals(WPA2) ? Protocol.RSN : Protocol.WPA);
// If password is empty, it should be left untouched
if (!TextUtils.isEmpty(mPassword)) {
config.preSharedKey = convertToQuotedString(mPassword);
}
} else if (security.equals(OPEN)) {
config.allowedKeyManagement.set(KeyMgmt.NONE);
}
}
private static boolean isHexWepKey(String wepKey) {
final int len = wepKey.length();
// WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
if (len != 10 && len != 26 && len != 58) {
return false;
}
for (int i = len - 1; i >= 0; i--) {
final char c = wepKey.charAt(i);
if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')) {
return false;
}
}
return true;
}
public void setCallback(AccessPointStateCallback callback) {
mCallback = callback;
}
void blockRefresh() {
mBlockRefresh++;
}
void unblockRefresh() {
if (--mBlockRefresh == 0 && mNeedsRefresh) {
requestRefresh();
}
}
private void requestRefresh() {
if (mBlockRefresh > 0) {
mNeedsRefresh = true;
return;
}
if (mCallback != null) {
mCallback.refreshAccessPointState();
}
mNeedsRefresh = false;
}
/**
* {@inheritDoc}
* @see #hashCode()
* @see #equals(Object)
*/
public int matches(int otherNetworkId, String otherBssid, String otherSsid,
String otherSecurity) {
// Whenever this method is touched, please ensure #equals and #hashCode
// still work with the changes here!
if (otherSsid == null) {
if (WifiLayer.LOGV) {
Log.w(TAG, "BSSID: " + otherBssid + ", SSID: " + otherSsid);
}
return MATCH_NONE;
}
/*
* If we both have 'security' set, it must match (an open network still
* has 'security' set to OPEN)
*/
if (security != null && otherSecurity != null) {
if (!security.equals(otherSecurity)) {
return MATCH_NONE;
}
}
// WifiConfiguration gives an empty bssid as a BSSID wildcard
if (TextUtils.isEmpty(otherBssid)) {
otherBssid = AccessPointState.BSSID_ANY;
}
final boolean networkIdMatches = networkId == otherNetworkId;
if (!networkIdMatches && networkId != NETWORK_ID_ANY && otherNetworkId != NETWORK_ID_ANY) {
// Network IDs don't match (e.g., 1 & 2 or unset & 1) and neither is a wildcard
return MATCH_NONE;
}
if (networkIdMatches && otherNetworkId != NETWORK_ID_NOT_SET
&& otherNetworkId != NETWORK_ID_ANY) {
// Network ID matches (they're set to the same ID)
return MATCH_EXACT;
}
// So now, network IDs aren't set or at least one is a wildcard
final boolean bssidMatches = bssid.equals(otherBssid);
final boolean otherBssidIsWildcard = otherBssid.equals(BSSID_ANY);
if (bssidMatches && !otherBssidIsWildcard) {
// BSSID matches (and neither is a wildcard)
return MATCH_STRONG;
}
if (!bssidMatches && !bssid.equals(BSSID_ANY) && !otherBssidIsWildcard) {
// BSSIDs don't match (e.g., 00:24:21:21:42:12 & 42:12:44:21:22:52)
// and neither is a wildcard
return MATCH_NONE;
}
// So now, BSSIDs are both wildcards
final boolean ssidMatches = ssid.equals(otherSsid);
if (ssidMatches) {
// SSID matches
return MATCH_WEAK;
}
return MATCH_NONE;
}
/**
* {@inheritDoc}
* @see #matches(int, String, String)
* @see #equals(Object)
*/
@Override
public int hashCode() {
// Two equal() objects must have same hashCode.
// With Wi-Fi, the broadest match is if two SSIDs are the same. The finer-grained matches
// imply this (for example, the same network IDs means the same WifiConfiguration which
// means the same SSID).
// See #matches for the exact matching algorithm we use.
return ssid != null ? ssid.hashCode() : 0;
}
/**
* {@inheritDoc}
* @see #matches(int, String, String)
* @see #hashCode()
*/
@Override
public boolean equals(Object o) {
if (!o.getClass().equals(getClass())) {
return false;
}
final AccessPointState other = (AccessPointState) o;
// To see which conditions cause two AccessPointStates to be equal, see
// where #matches returns MATCH_WEAK or greater.
return matches(other.networkId, other.bssid, other.ssid, other.security) >= MATCH_WEAK;
}
public int matchesWifiConfiguration(WifiConfiguration wifiConfig) {
String security = getWifiConfigurationSecurity(wifiConfig);
return matches(wifiConfig.networkId, wifiConfig.BSSID, wifiConfig.SSID, security);
}
String getSummarizedStatus() {
StringBuilder sb = mSummaryBuilder;
sb.delete(0, sb.length());
if (primary && status != null) {
buildSummary(sb, WifiStatus.getPrintable(mContext, status), true);
} else if (!seen) {
buildSummary(sb, SUMMARY_NOT_IN_RANGE, true);
// Remembered comes second in this case
if (!primary && configured) {
buildSummary(sb, SUMMARY_REMEMBERED, true);
}
} else {
if (configured && disabled) {
// The connection failure overrides all in this case
return SUMMARY_CONNECTION_FAILED;
}
// Remembered comes first in this case
if (!primary && configured) {
buildSummary(sb, SUMMARY_REMEMBERED, true);
}
// If it is seen (and not the primary), show the security type
String verboseSecurity = getVerboseSecurity();
if (verboseSecurity != null) {
buildSummary(sb, verboseSecurity, true);
}
}
return sb.toString();
}
private String getVerboseSecurity() {
if (WEP.equals(security)) {
return LOCALIZED_VERBOSE_WEP;
} else if (WPA.equals(security)) {
return LOCALIZED_VERBOSE_WPA;
} else if (WPA2.equals(security)) {
return LOCALIZED_VERBOSE_WPA2;
} else if (OPEN.equals(security)) {
return LOCALIZED_VERBOSE_OPEN;
} else {
return null;
}
}
private void buildSummary(StringBuilder sb, String string, boolean autoLowerCaseFirstLetter) {
if (sb.length() == 0) {
sb.append(string);
} else {
sb.append(", ");
if (autoLowerCaseFirstLetter) {
// Convert first letter to lowercase
sb.append(Character.toLowerCase(string.charAt(0))).append(string, 1,
string.length());
} else {
sb.append(string);
}
}
}
public int compareTo(AccessPointState other) {
// This ranks the states for displaying in the AP list, not for
// connecting to (wpa_supplicant does that using the WifiConfiguration's
// priority field).
// Clarity > efficiency, of this logic:
int comparison;
// Primary
comparison = (other.primary ? 1 : 0) - (primary ? 1 : 0);
if (comparison != 0) return comparison;
// Currently seen (similar to, but not always the same as within range)
comparison = (other.seen ? 1 : 0) - (seen ? 1 : 0);
if (comparison != 0) return comparison;
// Configured
comparison = (other.configured ? 1 : 0) - (configured ? 1 : 0);
if (comparison != 0) return comparison;
if (!configured) {
// Neither are configured
// Open network
comparison = (hasSecurity() ? 1 : 0) - (other.hasSecurity() ? 1 : 0);
if (comparison != 0) return comparison;
}
// Signal strength
comparison = (int) (other.signalForSorting - signalForSorting);
if (comparison != 0) return comparison;
// Alphabetical
return ssid.compareToIgnoreCase(other.ssid);
}
public String toString() {
return ssid + " (" + bssid + ", " + networkId + ", " + super.toString() + ")";
}
/** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bssid);
dest.writeInt(configured ? 1 : 0);
dest.writeInt(ipAddress);
dest.writeInt(linkSpeed);
dest.writeInt(networkId);
dest.writeInt(primary ? 1 : 0);
dest.writeInt(priority);
dest.writeInt(hiddenSsid ? 1 : 0);
dest.writeString(security);
dest.writeInt(seen ? 1 : 0);
dest.writeInt(disabled ? 1 : 0);
dest.writeInt(signal);
dest.writeString(ssid);
dest.writeString(status != null ? status.toString() : null);
dest.writeString(mPassword);
dest.writeInt(mConfigHadPassword ? 1 : 0);
dest.writeInt(mWepPasswordType);
}
/** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
/** Implement the Parcelable interface */
public static final Creator<AccessPointState> CREATOR =
new Creator<AccessPointState>() {
public AccessPointState createFromParcel(Parcel in) {
AccessPointState state = new AccessPointState();
state.bssid = in.readString();
state.configured = in.readInt() == 1;
state.ipAddress = in.readInt();
state.linkSpeed = in.readInt();
state.networkId = in.readInt();
state.primary = in.readInt() == 1;
state.priority = in.readInt();
state.hiddenSsid = in.readInt() == 1;
state.security = in.readString();
state.seen = in.readInt() == 1;
state.disabled = in.readInt() == 1;
state.signal = in.readInt();
state.ssid = in.readString();
String statusStr = in.readString();
if (statusStr != null) {
state.status = NetworkInfo.DetailedState.valueOf(statusStr);
}
state.mPassword = in.readString();
state.mConfigHadPassword = in.readInt() == 1;
state.mWepPasswordType = in.readInt();
return state;
}
public AccessPointState[] newArray(int size) {
return new AccessPointState[size];
}
};
}

View File

@@ -0,0 +1,180 @@
/*
* 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.wifi;
import com.android.settings.R;
import android.content.ContentResolver;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.provider.Settings.System;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class IpSettings extends PreferenceActivity implements Preference.OnPreferenceChangeListener {
private static final String KEY_USE_STATIC_IP = "use_static_ip";
private String[] mSettingNames = {
System.WIFI_STATIC_IP, System.WIFI_STATIC_GATEWAY, System.WIFI_STATIC_NETMASK,
System.WIFI_STATIC_DNS1, System.WIFI_STATIC_DNS2
};
private String[] mPreferenceKeys = {
"ip_address", "gateway", "netmask", "dns1", "dns2"
};
private CheckBoxPreference mUseStaticIpCheckBox;
private static final int MENU_ITEM_SAVE = Menu.FIRST;
private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.ip_settings);
mUseStaticIpCheckBox = (CheckBoxPreference) findPreference(KEY_USE_STATIC_IP);
for (int i = 0; i < mPreferenceKeys.length; i++) {
Preference preference = findPreference(mPreferenceKeys[i]);
preference.setOnPreferenceChangeListener(this);
}
}
@Override
protected void onResume() {
super.onResume();
updateUi();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
updateSettingsProvider();
}
return super.onKeyDown(keyCode, event);
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
String value = (String) newValue;
if (!isIpAddress(value)) {
Toast.makeText(this, R.string.wifi_ip_settings_invalid_ip, Toast.LENGTH_LONG).show();
return false;
}
preference.setSummary(value);
return true;
}
private boolean isIpAddress(String value) {
int start = 0;
int end = value.indexOf('.');
int numBlocks = 0;
while (start < value.length()) {
if (end == -1) {
end = value.length();
}
try {
int block = Integer.parseInt(value.substring(start, end));
if ((block > 255) || (block < 0)) {
return false;
}
} catch (NumberFormatException e) {
return false;
}
numBlocks++;
start = end + 1;
end = value.indexOf('.', start);
}
return numBlocks == 4;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_ITEM_SAVE, 0, R.string.wifi_ip_settings_menu_save)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(0, MENU_ITEM_CANCEL, 0, R.string.wifi_ip_settings_menu_cancel)
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_SAVE:
updateSettingsProvider();
finish();
return true;
case MENU_ITEM_CANCEL:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateUi() {
ContentResolver contentResolver = getContentResolver();
mUseStaticIpCheckBox.setChecked(System.getInt(contentResolver,
System.WIFI_USE_STATIC_IP, 0) != 0);
for (int i = 0; i < mSettingNames.length; i++) {
EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
String settingValue = System.getString(contentResolver, mSettingNames[i]);
preference.setText(settingValue);
preference.setSummary(settingValue);
}
}
private void updateSettingsProvider() {
ContentResolver contentResolver = getContentResolver();
System.putInt(contentResolver, System.WIFI_USE_STATIC_IP,
mUseStaticIpCheckBox.isChecked() ? 1 : 0);
for (int i = 0; i < mSettingNames.length; i++) {
EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
System.putString(contentResolver, mSettingNames[i], preference.getText());
}
}
}

View File

@@ -0,0 +1,188 @@
/*
* 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.wifi;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
import com.android.settings.R;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.preference.Preference;
import android.preference.CheckBoxPreference;
import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
public class WifiEnabler implements Preference.OnPreferenceChangeListener {
private static final boolean LOCAL_LOGD = Config.LOGD || WifiLayer.LOGV;
private static final String TAG = "SettingsWifiEnabler";
private final Context mContext;
private final WifiManager mWifiManager;
private final CheckBoxPreference mWifiCheckBoxPref;
private final CharSequence mOriginalSummary;
private final IntentFilter mWifiStateFilter;
private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
handleWifiStateChanged(
intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WIFI_STATE_UNKNOWN),
intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE,
WIFI_STATE_UNKNOWN));
} else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
handleNetworkStateChanged(
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
}
}
};
public WifiEnabler(Context context, WifiManager wifiManager,
CheckBoxPreference wifiCheckBoxPreference) {
mContext = context;
mWifiCheckBoxPref = wifiCheckBoxPreference;
mWifiManager = wifiManager;
mOriginalSummary = wifiCheckBoxPreference.getSummary();
wifiCheckBoxPreference.setPersistent(false);
mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
}
public void resume() {
int state = mWifiManager.getWifiState();
// This is the widget enabled state, not the preference toggled state
mWifiCheckBoxPref.setEnabled(state == WIFI_STATE_ENABLED || state == WIFI_STATE_DISABLED
|| state == WIFI_STATE_UNKNOWN);
mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
mWifiCheckBoxPref.setOnPreferenceChangeListener(this);
}
public void pause() {
mContext.unregisterReceiver(mWifiStateReceiver);
mWifiCheckBoxPref.setOnPreferenceChangeListener(null);
}
public boolean onPreferenceChange(Preference preference, Object value) {
// Turn on/off Wi-Fi
setWifiEnabled((Boolean) value);
// Don't update UI to opposite state until we're sure
return false;
}
private void setWifiEnabled(final boolean enable) {
// Disable button
mWifiCheckBoxPref.setEnabled(false);
if (!mWifiManager.setWifiEnabled(enable)) {
mWifiCheckBoxPref.setSummary(enable ? R.string.error_starting : R.string.error_stopping);
}
}
private void handleWifiStateChanged(int wifiState, int previousWifiState) {
if (LOCAL_LOGD) {
Log.d(TAG, "Received wifi state changed from "
+ getHumanReadableWifiState(previousWifiState) + " to "
+ getHumanReadableWifiState(wifiState));
}
if (wifiState == WIFI_STATE_DISABLED || wifiState == WIFI_STATE_ENABLED) {
mWifiCheckBoxPref.setChecked(wifiState == WIFI_STATE_ENABLED);
mWifiCheckBoxPref
.setSummary(wifiState == WIFI_STATE_DISABLED ? mOriginalSummary : null);
mWifiCheckBoxPref.setEnabled(isEnabledByDependency());
} else if (wifiState == WIFI_STATE_DISABLING || wifiState == WIFI_STATE_ENABLING) {
mWifiCheckBoxPref.setSummary(wifiState == WIFI_STATE_ENABLING ? R.string.wifi_starting
: R.string.wifi_stopping);
} else if (wifiState == WIFI_STATE_UNKNOWN) {
int message = R.string.wifi_error;
if (previousWifiState == WIFI_STATE_ENABLING) message = R.string.error_starting;
else if (previousWifiState == WIFI_STATE_DISABLING) message = R.string.error_stopping;
mWifiCheckBoxPref.setChecked(false);
mWifiCheckBoxPref.setSummary(message);
mWifiCheckBoxPref.setEnabled(true);
}
}
private void handleNetworkStateChanged(NetworkInfo networkInfo) {
if (LOCAL_LOGD) {
Log.d(TAG, "Received network state changed to " + networkInfo);
}
if (mWifiManager.isWifiEnabled()) {
String summary = WifiStatus.getStatus(mContext,
mWifiManager.getConnectionInfo().getSSID(), networkInfo.getDetailedState());
mWifiCheckBoxPref.setSummary(summary);
}
}
private boolean isEnabledByDependency() {
Preference dep = getDependencyPreference();
if (dep == null) {
return true;
}
return !dep.shouldDisableDependents();
}
private Preference getDependencyPreference() {
String depKey = mWifiCheckBoxPref.getDependency();
if (TextUtils.isEmpty(depKey)) {
return null;
}
return mWifiCheckBoxPref.getPreferenceManager().findPreference(depKey);
}
private static String getHumanReadableWifiState(int wifiState) {
switch (wifiState) {
case WIFI_STATE_DISABLED:
return "Disabled";
case WIFI_STATE_DISABLING:
return "Disabling";
case WIFI_STATE_ENABLED:
return "Enabled";
case WIFI_STATE_ENABLING:
return "Enabling";
case WIFI_STATE_UNKNOWN:
return "Unknown";
default:
return "Some other state!";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,438 @@
/*
* 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.wifi;
import com.android.settings.ProgressCategory;
import com.android.settings.R;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.Bundle;
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.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Settings screen for WiFi. This will be launched from the main system settings.
*/
public class WifiSettings extends PreferenceActivity implements WifiLayer.Callback,
DialogInterface.OnDismissListener {
private static final String TAG = "WifiSettings";
//============================
// Preference/activity member variables
//============================
private static final String INSTANCE_KEY_DIALOG_BUNDLE =
"com.android.settings.wifi.WifiSettings:dialogBundle";
/*
* We don't use Activity's dialog management because AlertDialog isn't fully
* able to change many of its features after it's been created, and the
* dialog management only creates once.
*/
private Dialog mDialog;
private static final String KEY_ADD_OTHER_NETWORK = "add_other_network";
private static final int CONTEXT_MENU_ID_CONNECT = Menu.FIRST;
private static final int CONTEXT_MENU_ID_FORGET = Menu.FIRST + 1;
private static final int CONTEXT_MENU_ID_CHANGE_PASSWORD = Menu.FIRST + 2;
private static final int MENU_ID_SCAN = Menu.FIRST;
private static final int MENU_ID_ADVANCED = Menu.FIRST + 1;
private static final String KEY_WIFI_ENABLED = "wifi_enabled";
private static final String KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED =
"open_network_notifications_enabled";
private static final String KEY_ACCESS_POINTS = "access_points";
private ProgressCategory mApCategory;
private CheckBoxPreference mWifiEnabled;
private WifiEnabler mWifiEnabler;
private CheckBoxPreference mOpenNetworkNotificationsEnabled;
private Preference mAddOtherNetwork;
private WeakHashMap<AccessPointState, AccessPointPreference> mAps;
//============================
// Wifi member variables
//============================
private WifiLayer mWifiLayer;
//============================
// Activity lifecycle
//============================
public WifiSettings() {
mAps = new WeakHashMap<AccessPointState, AccessPointPreference>();
mWifiLayer = new WifiLayer(this, this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onCreatePreferences();
mWifiLayer.onCreate();
onCreatedWifi();
mWifiLayer.onCreatedCallback();
}
/**
* Shouldn't have any dependency on the wifi layer.
*/
private void onCreatePreferences() {
addPreferencesFromResource(R.xml.wifi_settings);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
mApCategory = (ProgressCategory) preferenceScreen.findPreference(KEY_ACCESS_POINTS);
// We don't want the ordering to be the order preferences are added,
// instead we want*:
// 1) preferred, visible APs
// 2) visible APs
// 3) preferred, APs out of range
// * this ordering logic is in AccessPointPreference's compareTo
mApCategory.setOrderingAsAdded(false);
mWifiEnabled = (CheckBoxPreference) preferenceScreen.findPreference(KEY_WIFI_ENABLED);
mWifiEnabler = new WifiEnabler(this, (WifiManager) getSystemService(WIFI_SERVICE),
mWifiEnabled);
mOpenNetworkNotificationsEnabled = (CheckBoxPreference) preferenceScreen
.findPreference(KEY_OPEN_NETWORK_NOTIFICATIONS_ENABLED);
mOpenNetworkNotificationsEnabled.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
mAddOtherNetwork = preferenceScreen.findPreference(KEY_ADD_OTHER_NETWORK);
registerForContextMenu(getListView());
}
private void onCreatedWifi() {
}
@Override
protected void onResume() {
super.onResume();
mWifiLayer.onResume();
mWifiEnabler.resume();
}
@Override
protected void onPause() {
super.onPause();
mWifiLayer.onPause();
mWifiEnabler.pause();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mDialog != null) {
mDialog.dismiss();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_ID_SCAN, 0, R.string.scan_wifi)
.setIcon(R.drawable.ic_menu_scan_network);
menu.add(0, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
.setIcon(R.drawable.ic_menu_manage);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case MENU_ID_SCAN:
mWifiLayer.attemptScan();
return true;
case MENU_ID_ADVANCED:
Intent intent = new Intent(this, IpSettings.class);
startActivity(intent);
return true;
default:
return false;
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mDialog != null) {
Bundle dialogBundle = mDialog.onSaveInstanceState();
outState.putBundle(INSTANCE_KEY_DIALOG_BUNDLE, dialogBundle);
}
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
Bundle dialogBundle = state.getBundle(INSTANCE_KEY_DIALOG_BUNDLE);
if (dialogBundle != null) {
mDialog = new AccessPointDialog(this, mWifiLayer);
mDialog.onRestoreInstanceState(dialogBundle);
showDialog(mDialog);
}
}
/**
* {@inheritDoc}
*/
public void onDismiss(DialogInterface dialog) {
if (dialog == mDialog) {
mDialog = null;
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AccessPointState state = getStateFromMenuInfo(menuInfo);
if (state == null) {
return;
}
menu.setHeaderTitle(state.getHumanReadableSsid());
if (state.isConnectable()) {
menu.add(0, CONTEXT_MENU_ID_CONNECT, 0, R.string.wifi_context_menu_connect);
}
if (state.isForgetable()) {
menu.add(0, CONTEXT_MENU_ID_FORGET, 1, R.string.wifi_context_menu_forget);
if (state.hasPassword()) {
menu.add(0, CONTEXT_MENU_ID_CHANGE_PASSWORD, 2,
R.string.wifi_context_menu_change_password);
}
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AccessPointState state = getStateFromMenuInfo(item.getMenuInfo());
if (state == null) {
return false;
}
switch (item.getItemId()) {
case CONTEXT_MENU_ID_CONNECT:
connectToNetwork(state);
return true;
case CONTEXT_MENU_ID_FORGET:
mWifiLayer.forgetNetwork(state);
return true;
case CONTEXT_MENU_ID_CHANGE_PASSWORD:
showAccessPointDialog(state, AccessPointDialog.MODE_CONFIGURE);
return true;
default:
return false;
}
}
/**
* Decides what needs to happen to connect to a particular access point. If
* it is secured and doesn't already have a password, it will bring up a
* password box. Otherwise it will just connect.
*/
private void connectToNetwork(AccessPointState state) {
if (state.hasSecurity() && !state.hasPassword()) {
showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
} else {
mWifiLayer.connectToNetwork(state);
}
}
private AccessPointState getStateFromMenuInfo(ContextMenuInfo menuInfo) {
if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
return null;
}
AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
adapterMenuInfo.position);
if (pref == null || !(pref instanceof AccessPointPreference)) {
return null;
}
return ((AccessPointPreference) pref).getAccessPointState();
}
//============================
// Preference callbacks
//============================
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
if (preference == mAddOtherNetwork) {
showAddOtherNetworkDialog();
} else if (preference == mOpenNetworkNotificationsEnabled) {
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
mOpenNetworkNotificationsEnabled.isChecked() ? 1 : 0);
} else if (preference instanceof AccessPointPreference) {
AccessPointState state = ((AccessPointPreference) preference).getAccessPointState();
showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
}
return false;
}
//============================
// Wifi-related
//============================
public WifiLayer getWifiLayer() {
return mWifiLayer;
}
private void showAddOtherNetworkDialog() {
AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
dialog.setState(new AccessPointState(this));
dialog.setMode(AccessPointDialog.MODE_CONFIGURE);
dialog.setTitle(R.string.wifi_add_other_network);
dialog.setAutoSecurityAllowed(false);
showDialog(dialog);
}
public void showAccessPointDialog(AccessPointState state, int mode) {
AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
dialog.setMode(mode);
dialog.setState(state);
showDialog(dialog);
}
private void showDialog(Dialog dialog) {
// Have only one dialog open at a time
if (mDialog != null) {
mDialog.dismiss();
}
mDialog = dialog;
dialog.setOnDismissListener(this);
if (dialog != null) {
dialog.show();
}
}
//============================
// Wifi callbacks
//============================
public void onError(int messageResId) {
Toast.makeText(this, messageResId, Toast.LENGTH_LONG).show();
}
public void onScanningStatusChanged(boolean started) {
mApCategory.setProgress(started);
}
public void onAccessPointSetChanged(AccessPointState ap, boolean added) {
AccessPointPreference pref = mAps.get(ap);
if (WifiLayer.LOGV) {
Log.v(TAG, "onAccessPointSetChanged with " + ap + " and "
+ (added ? "added" : "removed") + ", found pref " + pref);
}
if (added) {
if (pref == null) {
pref = new AccessPointPreference(this, ap);
mAps.put(ap, pref);
} else {
pref.setEnabled(true);
}
mApCategory.addPreference(pref);
} else {
mAps.remove(ap);
if (pref != null) {
mApCategory.removePreference(pref);
}
}
}
public void onAccessPointsStateChanged(boolean enabled) {
if (enabled) {
mApCategory.setEnabled(true);
} else {
mApCategory.removeAll();
mAps.clear();
}
mAddOtherNetwork.setEnabled(enabled);
}
public void onRetryPassword(AccessPointState ap) {
if ((mDialog != null) && mDialog.isShowing()) {
// If we're already showing a dialog, ignore this request
return;
}
showAccessPointDialog(ap, AccessPointDialog.MODE_RETRY_PASSWORD);
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.wifi;
import com.android.settings.R;
import android.content.Context;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.text.TextUtils;
public class WifiStatus {
// e.g., "Connecting"
public static String sScanning;
public static String sConnecting;
public static String sAuthenticating;
public static String sObtainingIp;
public static String sConnected;
public static String sDisconnecting;
public static String sDisconnected;
public static String sFailed;
// e.g., "Connecting to %1$s"
public static String sScanningFragment;
public static String sConnectingFragment;
public static String sAuthenticatingFragment;
public static String sObtainingIpFragment;
public static String sConnectedFragment;
public static String sDisconnectingFragment;
public static String sDisconnectedFragment;
public static String sFailedFragment;
private static void fillStrings(Context context) {
sScanning = context.getString(R.string.status_scanning);
sConnecting = context.getString(R.string.status_connecting);
sAuthenticating = context.getString(R.string.status_authenticating);
sObtainingIp = context.getString(R.string.status_obtaining_ip);
sConnected = context.getString(R.string.status_connected);
sDisconnecting = context.getString(R.string.status_disconnecting);
sDisconnected = context.getString(R.string.status_disconnected);
sFailed = context.getString(R.string.status_failed);
sScanningFragment = context.getString(R.string.fragment_status_scanning);
sConnectingFragment = context.getString(R.string.fragment_status_connecting);
sAuthenticatingFragment = context.getString(R.string.fragment_status_authenticating);
sObtainingIpFragment = context.getString(R.string.fragment_status_obtaining_ip);
sConnectedFragment = context.getString(R.string.fragment_status_connected);
sDisconnectingFragment = context.getString(R.string.fragment_status_disconnecting);
sDisconnectedFragment = context.getString(R.string.fragment_status_disconnected);
sFailedFragment = context.getString(R.string.fragment_status_failed);
}
public static String getStatus(Context context, String ssid,
NetworkInfo.DetailedState detailedState) {
if (!TextUtils.isEmpty(ssid) && isLiveConnection(detailedState)) {
return getPrintableFragment(context, detailedState, ssid);
} else {
return getPrintable(context, detailedState);
}
}
public static boolean isLiveConnection(NetworkInfo.DetailedState detailedState) {
return detailedState != NetworkInfo.DetailedState.DISCONNECTED
&& detailedState != NetworkInfo.DetailedState.FAILED
&& detailedState != NetworkInfo.DetailedState.IDLE
&& detailedState != NetworkInfo.DetailedState.SCANNING;
}
public static String getPrintable(Context context,
NetworkInfo.DetailedState detailedState) {
if (sScanning == null) {
fillStrings(context);
}
switch (detailedState) {
case AUTHENTICATING:
return sAuthenticating;
case CONNECTED:
return sConnected;
case CONNECTING:
return sConnecting;
case DISCONNECTED:
return sDisconnected;
case DISCONNECTING:
return sDisconnecting;
case FAILED:
return sFailed;
case OBTAINING_IPADDR:
return sObtainingIp;
case SCANNING:
return sScanning;
default:
return null;
}
}
public static String getPrintableFragment(Context context,
NetworkInfo.DetailedState detailedState, String apName) {
if (sScanningFragment == null) {
fillStrings(context);
}
String fragment = null;
switch (detailedState) {
case AUTHENTICATING:
fragment = sAuthenticatingFragment;
break;
case CONNECTED:
fragment = sConnectedFragment;
break;
case CONNECTING:
fragment = sConnectingFragment;
break;
case DISCONNECTED:
fragment = sDisconnectedFragment;
break;
case DISCONNECTING:
fragment = sDisconnectingFragment;
break;
case FAILED:
fragment = sFailedFragment;
break;
case OBTAINING_IPADDR:
fragment = sObtainingIpFragment;
break;
case SCANNING:
fragment = sScanningFragment;
break;
}
return String.format(fragment, apName);
}
}