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