/* * Copyright (C) 2015 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.messaging.ui.appsettings; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Telephony; import androidx.core.app.NavUtils; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.android.messaging.R; import com.android.messaging.datamodel.data.ParticipantData; import com.android.messaging.sms.ApnDatabase; import com.android.messaging.sms.BugleApnSettingsLoader; import com.android.messaging.ui.BugleActionBarActivity; import com.android.messaging.ui.UIIntents; import com.android.messaging.util.OsUtil; import com.android.messaging.util.PhoneUtils; public class ApnSettingsActivity extends BugleActionBarActivity { private static final int DIALOG_RESTORE_DEFAULTAPN = 1001; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportActionBar().setDisplayHomeAsUpEnabled(true); // Display the fragment as the main content. final ApnSettingsFragment fragment = new ApnSettingsFragment(); fragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID)); getFragmentManager().beginTransaction() .replace(android.R.id.content, fragment) .commit(); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; } return super.onOptionsItemSelected(item); } @Override protected Dialog onCreateDialog(int id) { if (id == DIALOG_RESTORE_DEFAULTAPN) { ProgressDialog dialog = new ProgressDialog(this); dialog.setMessage(getResources().getString(R.string.restore_default_apn)); dialog.setCancelable(false); return dialog; } return null; } public static class ApnSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener { public static final String EXTRA_POSITION = "position"; public static final String APN_ID = "apn_id"; private static final String[] APN_PROJECTION = { Telephony.Carriers._ID, // 0 Telephony.Carriers.NAME, // 1 Telephony.Carriers.APN, // 2 Telephony.Carriers.TYPE // 3 }; 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 TYPES_INDEX = 3; private static final int MENU_NEW = Menu.FIRST; private static final int MENU_RESTORE = Menu.FIRST + 1; private static final int EVENT_RESTORE_DEFAULTAPN_START = 1; private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2; private static boolean mRestoreDefaultApnMode; private RestoreApnUiHandler mRestoreApnUiHandler; private RestoreApnProcessHandler mRestoreApnProcessHandler; private HandlerThread mRestoreDefaultApnThread; private String mSelectedKey; private static final ContentValues sCurrentNullMap; private static final ContentValues sCurrentSetMap; private UserManager mUm; private boolean mUnavailable; private int mSubId; static { sCurrentNullMap = new ContentValues(1); sCurrentNullMap.putNull(Telephony.Carriers.CURRENT); sCurrentSetMap = new ContentValues(1); sCurrentSetMap.put(Telephony.Carriers.CURRENT, "2"); // 2 for user-selected APN, // 1 for Bugle-selected APN } private SQLiteDatabase mDatabase; public void setSubId(final int subId) { mSubId = subId; } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mDatabase = ApnDatabase.getApnDatabase().getWritableDatabase(); if (OsUtil.isAtLeastL()) { mUm = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { setHasOptionsMenu(true); } } else { setHasOptionsMenu(true); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final ListView lv = (ListView) getView().findViewById(android.R.id.list); TextView empty = (TextView) getView().findViewById(android.R.id.empty); if (empty != null) { empty.setText(R.string.apn_settings_not_available); lv.setEmptyView(empty); } if (OsUtil.isAtLeastL() && mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) { mUnavailable = true; setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity())); return; } addPreferencesFromResource(R.xml.apn_settings); lv.setItemsCanFocus(true); } @Override public void onResume() { super.onResume(); if (mUnavailable) { return; } if (!mRestoreDefaultApnMode) { fillList(); } } @Override public void onPause() { super.onPause(); if (mUnavailable) { return; } } @Override public void onDestroy() { super.onDestroy(); if (mRestoreDefaultApnThread != null) { mRestoreDefaultApnThread.quit(); } } private void fillList() { final String mccMnc = PhoneUtils.getMccMncString(PhoneUtils.get(mSubId).getMccMnc()); new AsyncTask() { @Override protected Cursor doInBackground(Void... params) { String selection = Telephony.Carriers.NUMERIC + " =?"; String[] selectionArgs = new String[]{ mccMnc }; final Cursor cursor = mDatabase.query(ApnDatabase.APN_TABLE, APN_PROJECTION, selection, selectionArgs, null, null, null, null); return cursor; } @Override protected void onPostExecute(Cursor cursor) { if (cursor != null) { try { PreferenceGroup apnList = (PreferenceGroup) findPreference(getString(R.string.apn_list_pref_key)); apnList.removeAll(); mSelectedKey = BugleApnSettingsLoader.getFirstTryApn(mDatabase, mccMnc); while (cursor.moveToNext()) { String name = cursor.getString(NAME_INDEX); String apn = cursor.getString(APN_INDEX); String key = cursor.getString(ID_INDEX); String type = cursor.getString(TYPES_INDEX); if (BugleApnSettingsLoader.isValidApnType(type, BugleApnSettingsLoader.APN_TYPE_MMS)) { ApnPreference pref = new ApnPreference(getActivity()); pref.setKey(key); pref.setTitle(name); pref.setSummary(apn); pref.setPersistent(false); pref.setOnPreferenceChangeListener(ApnSettingsFragment.this); pref.setSelectable(true); // Turn on the radio button for the currently selected APN. If // there is no selected APN, don't select an APN. if ((mSelectedKey != null && mSelectedKey.equals(key))) { pref.setChecked(); } apnList.addPreference(pref); } } } finally { cursor.close(); } } } }.execute((Void) null); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (!mUnavailable) { menu.add(0, MENU_NEW, 0, getResources().getString(R.string.menu_new_apn)) .setIcon(R.drawable.ic_add_gray) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); menu.add(0, MENU_RESTORE, 0, getResources().getString(R.string.menu_restore_default_apn)) .setIcon(android.R.drawable.ic_menu_upload); } super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_NEW: addNewApn(); return true; case MENU_RESTORE: restoreDefaultApn(); return true; } return super.onOptionsItemSelected(item); } private void addNewApn() { startActivity(UIIntents.get().getApnEditorIntent(getActivity(), null, mSubId)); } @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { startActivity( UIIntents.get().getApnEditorIntent(getActivity(), preference.getKey(), mSubId)); return true; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (newValue instanceof String) { setSelectedApnKey((String) newValue); } return true; } // current=2 means user selected APN private static final String UPDATE_SELECTION = Telephony.Carriers.CURRENT + " =?"; private static final String[] UPDATE_SELECTION_ARGS = new String[] { "2" }; private void setSelectedApnKey(final String key) { mSelectedKey = key; // Make database changes not on the UI thread new AsyncTask() { @Override protected Void doInBackground(Void... params) { // null out the previous "current=2" APN mDatabase.update(ApnDatabase.APN_TABLE, sCurrentNullMap, UPDATE_SELECTION, UPDATE_SELECTION_ARGS); // set the new "current" APN (2) String selection = Telephony.Carriers._ID + " =?"; String[] selectionArgs = new String[]{ key }; mDatabase.update(ApnDatabase.APN_TABLE, sCurrentSetMap, selection, selectionArgs); return null; } }.execute((Void) null); } private boolean restoreDefaultApn() { getActivity().showDialog(DIALOG_RESTORE_DEFAULTAPN); mRestoreDefaultApnMode = true; if (mRestoreApnUiHandler == null) { mRestoreApnUiHandler = new RestoreApnUiHandler(); } if (mRestoreApnProcessHandler == null || mRestoreDefaultApnThread == null) { mRestoreDefaultApnThread = new HandlerThread( "Restore default APN Handler: Process Thread"); mRestoreDefaultApnThread.start(); mRestoreApnProcessHandler = new RestoreApnProcessHandler( mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler); } mRestoreApnProcessHandler.sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START); return true; } private class RestoreApnUiHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_RESTORE_DEFAULTAPN_COMPLETE: fillList(); getPreferenceScreen().setEnabled(true); mRestoreDefaultApnMode = false; final Activity activity = getActivity(); activity.dismissDialog(DIALOG_RESTORE_DEFAULTAPN); Toast.makeText(activity, getResources().getString( R.string.restore_default_apn_completed), Toast.LENGTH_LONG) .show(); break; } } } private class RestoreApnProcessHandler extends Handler { private Handler mCachedRestoreApnUiHandler; public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) { super(looper); this.mCachedRestoreApnUiHandler = restoreApnUiHandler; } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_RESTORE_DEFAULTAPN_START: ApnDatabase.forceBuildAndLoadApnTables(); mCachedRestoreApnUiHandler.sendEmptyMessage( EVENT_RESTORE_DEFAULTAPN_COMPLETE); break; } } } } }