1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings; 18 19 import android.app.Activity; 20 import android.app.Dialog; 21 import android.app.ProgressDialog; 22 import android.content.BroadcastReceiver; 23 import android.content.ContentResolver; 24 import android.content.ContentUris; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.database.Cursor; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.os.Handler; 33 import android.os.HandlerThread; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.UserManager; 37 import android.preference.Preference; 38 import android.preference.PreferenceActivity; 39 import android.preference.PreferenceGroup; 40 import android.preference.PreferenceScreen; 41 import android.provider.Telephony; 42 import android.util.Log; 43 import android.view.LayoutInflater; 44 import android.view.Menu; 45 import android.view.MenuInflater; 46 import android.view.MenuItem; 47 import android.view.View; 48 import android.widget.TextView; 49 import android.widget.Toast; 50 51 import com.android.internal.telephony.Phone; 52 import com.android.internal.telephony.PhoneConstants; 53 import com.android.internal.telephony.TelephonyIntents; 54 import com.android.internal.telephony.TelephonyProperties; 55 56 import java.util.ArrayList; 57 58 public class ApnSettings extends SettingsPreferenceFragment implements 59 Preference.OnPreferenceChangeListener { 60 static final String TAG = "ApnSettings"; 61 62 public static final String EXTRA_POSITION = "position"; 63 public static final String RESTORE_CARRIERS_URI = 64 "content://telephony/carriers/restore"; 65 public static final String PREFERRED_APN_URI = 66 "content://telephony/carriers/preferapn"; 67 68 public static final String APN_ID = "apn_id"; 69 70 private static final int ID_INDEX = 0; 71 private static final int NAME_INDEX = 1; 72 private static final int APN_INDEX = 2; 73 private static final int TYPES_INDEX = 3; 74 75 private static final int MENU_NEW = Menu.FIRST; 76 private static final int MENU_RESTORE = Menu.FIRST + 1; 77 78 private static final int EVENT_RESTORE_DEFAULTAPN_START = 1; 79 private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2; 80 81 private static final int DIALOG_RESTORE_DEFAULTAPN = 1001; 82 83 private static final Uri DEFAULTAPN_URI = Uri.parse(RESTORE_CARRIERS_URI); 84 private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); 85 86 private static boolean mRestoreDefaultApnMode; 87 88 private RestoreApnUiHandler mRestoreApnUiHandler; 89 private RestoreApnProcessHandler mRestoreApnProcessHandler; 90 private HandlerThread mRestoreDefaultApnThread; 91 92 private UserManager mUm; 93 94 private String mSelectedKey; 95 96 private IntentFilter mMobileStateFilter; 97 98 private boolean mUnavailable; 99 100 private final BroadcastReceiver mMobileStateReceiver = new BroadcastReceiver() { 101 @Override 102 public void onReceive(Context context, Intent intent) { 103 if (intent.getAction().equals( 104 TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { 105 PhoneConstants.DataState state = getMobileDataState(intent); 106 switch (state) { 107 case CONNECTED: 108 if (!mRestoreDefaultApnMode) { 109 fillList(); 110 } else { 111 showDialog(DIALOG_RESTORE_DEFAULTAPN); 112 } 113 break; 114 } 115 } 116 } 117 }; 118 119 private static PhoneConstants.DataState getMobileDataState(Intent intent) { 120 String str = intent.getStringExtra(PhoneConstants.STATE_KEY); 121 if (str != null) { 122 return Enum.valueOf(PhoneConstants.DataState.class, str); 123 } else { 124 return PhoneConstants.DataState.DISCONNECTED; 125 } 126 } 127 128 @Override 129 public void onCreate(Bundle icicle) { 130 super.onCreate(icicle); 131 132 mUm = (UserManager) getSystemService(Context.USER_SERVICE); 133 134 mMobileStateFilter = new IntentFilter( 135 TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); 136 137 if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { 138 setHasOptionsMenu(true); 139 } 140 } 141 142 @Override 143 public void onActivityCreated(Bundle savedInstanceState) { 144 super.onActivityCreated(savedInstanceState); 145 146 TextView empty = (TextView) getView().findViewById(android.R.id.empty); 147 if (empty != null) { 148 empty.setText(R.string.apn_settings_not_available); 149 getListView().setEmptyView(empty); 150 } 151 152 if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { 153 mUnavailable = true; 154 setPreferenceScreen(new PreferenceScreen(getActivity(), null)); 155 return; 156 } 157 158 addPreferencesFromResource(R.xml.apn_settings); 159 160 getListView().setItemsCanFocus(true); 161 } 162 163 @Override 164 public void onResume() { 165 super.onResume(); 166 167 if (mUnavailable) { 168 return; 169 } 170 171 getActivity().registerReceiver(mMobileStateReceiver, mMobileStateFilter); 172 173 if (!mRestoreDefaultApnMode) { 174 fillList(); 175 } 176 } 177 178 @Override 179 public void onPause() { 180 super.onPause(); 181 182 if (mUnavailable) { 183 return; 184 } 185 186 getActivity().unregisterReceiver(mMobileStateReceiver); 187 } 188 189 @Override 190 public void onDestroy() { 191 super.onDestroy(); 192 193 if (mRestoreDefaultApnThread != null) { 194 mRestoreDefaultApnThread.quit(); 195 } 196 } 197 198 private void fillList() { 199 String where = "numeric=\"" 200 + android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "") 201 + "\""; 202 203 Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] { 204 "_id", "name", "apn", "type"}, where, null, 205 Telephony.Carriers.DEFAULT_SORT_ORDER); 206 207 if (cursor != null) { 208 PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list"); 209 apnList.removeAll(); 210 211 ArrayList<Preference> mmsApnList = new ArrayList<Preference>(); 212 213 mSelectedKey = getSelectedApnKey(); 214 cursor.moveToFirst(); 215 while (!cursor.isAfterLast()) { 216 String name = cursor.getString(NAME_INDEX); 217 String apn = cursor.getString(APN_INDEX); 218 String key = cursor.getString(ID_INDEX); 219 String type = cursor.getString(TYPES_INDEX); 220 221 ApnPreference pref = new ApnPreference(getActivity()); 222 223 pref.setKey(key); 224 pref.setTitle(name); 225 pref.setSummary(apn); 226 pref.setPersistent(false); 227 pref.setOnPreferenceChangeListener(this); 228 229 boolean selectable = ((type == null) || !type.equals("mms")); 230 pref.setSelectable(selectable); 231 if (selectable) { 232 if ((mSelectedKey != null) && mSelectedKey.equals(key)) { 233 pref.setChecked(); 234 } 235 apnList.addPreference(pref); 236 } else { 237 mmsApnList.add(pref); 238 } 239 cursor.moveToNext(); 240 } 241 cursor.close(); 242 243 for (Preference preference : mmsApnList) { 244 apnList.addPreference(preference); 245 } 246 } 247 } 248 249 @Override 250 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 251 if (!mUnavailable) { 252 menu.add(0, MENU_NEW, 0, 253 getResources().getString(R.string.menu_new)) 254 .setIcon(android.R.drawable.ic_menu_add) 255 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 256 menu.add(0, MENU_RESTORE, 0, 257 getResources().getString(R.string.menu_restore)) 258 .setIcon(android.R.drawable.ic_menu_upload); 259 } 260 261 super.onCreateOptionsMenu(menu, inflater); 262 } 263 264 @Override 265 public boolean onOptionsItemSelected(MenuItem item) { 266 switch (item.getItemId()) { 267 case MENU_NEW: 268 addNewApn(); 269 return true; 270 271 case MENU_RESTORE: 272 restoreDefaultApn(); 273 return true; 274 } 275 return super.onOptionsItemSelected(item); 276 } 277 278 private void addNewApn() { 279 startActivity(new Intent(Intent.ACTION_INSERT, Telephony.Carriers.CONTENT_URI)); 280 } 281 282 @Override 283 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 284 int pos = Integer.parseInt(preference.getKey()); 285 Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos); 286 startActivity(new Intent(Intent.ACTION_EDIT, url)); 287 return true; 288 } 289 290 public boolean onPreferenceChange(Preference preference, Object newValue) { 291 Log.d(TAG, "onPreferenceChange(): Preference - " + preference 292 + ", newValue - " + newValue + ", newValue type - " 293 + newValue.getClass()); 294 if (newValue instanceof String) { 295 setSelectedApnKey((String) newValue); 296 } 297 298 return true; 299 } 300 301 private void setSelectedApnKey(String key) { 302 mSelectedKey = key; 303 ContentResolver resolver = getContentResolver(); 304 305 ContentValues values = new ContentValues(); 306 values.put(APN_ID, mSelectedKey); 307 resolver.update(PREFERAPN_URI, values, null, null); 308 } 309 310 private String getSelectedApnKey() { 311 String key = null; 312 313 Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] {"_id"}, 314 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); 315 if (cursor.getCount() > 0) { 316 cursor.moveToFirst(); 317 key = cursor.getString(ID_INDEX); 318 } 319 cursor.close(); 320 return key; 321 } 322 323 private boolean restoreDefaultApn() { 324 showDialog(DIALOG_RESTORE_DEFAULTAPN); 325 mRestoreDefaultApnMode = true; 326 327 if (mRestoreApnUiHandler == null) { 328 mRestoreApnUiHandler = new RestoreApnUiHandler(); 329 } 330 331 if (mRestoreApnProcessHandler == null || 332 mRestoreDefaultApnThread == null) { 333 mRestoreDefaultApnThread = new HandlerThread( 334 "Restore default APN Handler: Process Thread"); 335 mRestoreDefaultApnThread.start(); 336 mRestoreApnProcessHandler = new RestoreApnProcessHandler( 337 mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler); 338 } 339 340 mRestoreApnProcessHandler 341 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START); 342 return true; 343 } 344 345 private class RestoreApnUiHandler extends Handler { 346 @Override 347 public void handleMessage(Message msg) { 348 switch (msg.what) { 349 case EVENT_RESTORE_DEFAULTAPN_COMPLETE: 350 Activity activity = getActivity(); 351 if (activity == null) { 352 mRestoreDefaultApnMode = false; 353 return; 354 } 355 fillList(); 356 getPreferenceScreen().setEnabled(true); 357 mRestoreDefaultApnMode = false; 358 removeDialog(DIALOG_RESTORE_DEFAULTAPN); 359 Toast.makeText( 360 activity, 361 getResources().getString( 362 R.string.restore_default_apn_completed), 363 Toast.LENGTH_LONG).show(); 364 break; 365 } 366 } 367 } 368 369 private class RestoreApnProcessHandler extends Handler { 370 private Handler mRestoreApnUiHandler; 371 372 public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) { 373 super(looper); 374 this.mRestoreApnUiHandler = restoreApnUiHandler; 375 } 376 377 @Override 378 public void handleMessage(Message msg) { 379 switch (msg.what) { 380 case EVENT_RESTORE_DEFAULTAPN_START: 381 ContentResolver resolver = getContentResolver(); 382 resolver.delete(DEFAULTAPN_URI, null, null); 383 mRestoreApnUiHandler 384 .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE); 385 break; 386 } 387 } 388 } 389 390 @Override 391 public Dialog onCreateDialog(int id) { 392 if (id == DIALOG_RESTORE_DEFAULTAPN) { 393 ProgressDialog dialog = new ProgressDialog(getActivity()); 394 dialog.setMessage(getResources().getString(R.string.restore_default_apn)); 395 dialog.setCancelable(false); 396 return dialog; 397 } 398 return null; 399 } 400 } 401