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
17package com.android.settings;
18
19import android.app.Dialog;
20import android.app.ProgressDialog;
21import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.ContentUris;
24import android.content.ContentValues;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.database.Cursor;
29import android.net.Uri;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.HandlerThread;
33import android.os.Looper;
34import android.os.Message;
35import android.preference.Preference;
36import android.preference.PreferenceActivity;
37import android.preference.PreferenceGroup;
38import android.preference.PreferenceScreen;
39import android.provider.Telephony;
40import android.util.Log;
41import android.view.Menu;
42import android.view.MenuItem;
43import android.widget.Toast;
44
45import com.android.internal.telephony.Phone;
46import com.android.internal.telephony.TelephonyIntents;
47import com.android.internal.telephony.TelephonyProperties;
48
49import java.util.ArrayList;
50
51public class ApnSettings extends PreferenceActivity implements
52        Preference.OnPreferenceChangeListener {
53    static final String TAG = "ApnSettings";
54
55    public static final String EXTRA_POSITION = "position";
56    public static final String RESTORE_CARRIERS_URI =
57        "content://telephony/carriers/restore";
58    public static final String PREFERRED_APN_URI =
59        "content://telephony/carriers/preferapn";
60
61    public static final String APN_ID = "apn_id";
62
63    private static final int ID_INDEX = 0;
64    private static final int NAME_INDEX = 1;
65    private static final int APN_INDEX = 2;
66    private static final int TYPES_INDEX = 3;
67
68    private static final int MENU_NEW = Menu.FIRST;
69    private static final int MENU_RESTORE = Menu.FIRST + 1;
70
71    private static final int EVENT_RESTORE_DEFAULTAPN_START = 1;
72    private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2;
73
74    private static final int DIALOG_RESTORE_DEFAULTAPN = 1001;
75
76    private static final Uri DEFAULTAPN_URI = Uri.parse(RESTORE_CARRIERS_URI);
77    private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI);
78
79    private static boolean mRestoreDefaultApnMode;
80
81    private RestoreApnUiHandler mRestoreApnUiHandler;
82    private RestoreApnProcessHandler mRestoreApnProcessHandler;
83
84    private String mSelectedKey;
85
86    private IntentFilter mMobileStateFilter;
87
88    private final BroadcastReceiver mMobileStateReceiver = new BroadcastReceiver() {
89        @Override
90        public void onReceive(Context context, Intent intent) {
91            if (intent.getAction().equals(
92                    TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
93                Phone.DataState state = getMobileDataState(intent);
94                switch (state) {
95                case CONNECTED:
96                    if (!mRestoreDefaultApnMode) {
97                        fillList();
98                    } else {
99                        showDialog(DIALOG_RESTORE_DEFAULTAPN);
100                    }
101                    break;
102                }
103            }
104        }
105    };
106
107    private static Phone.DataState getMobileDataState(Intent intent) {
108        String str = intent.getStringExtra(Phone.STATE_KEY);
109        if (str != null) {
110            return Enum.valueOf(Phone.DataState.class, str);
111        } else {
112            return Phone.DataState.DISCONNECTED;
113        }
114    }
115
116    @Override
117    protected void onCreate(Bundle icicle) {
118        super.onCreate(icicle);
119
120        addPreferencesFromResource(R.xml.apn_settings);
121        getListView().setItemsCanFocus(true);
122
123        mMobileStateFilter = new IntentFilter(
124                TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
125    }
126
127    @Override
128    protected void onResume() {
129        super.onResume();
130
131        registerReceiver(mMobileStateReceiver, mMobileStateFilter);
132
133        if (!mRestoreDefaultApnMode) {
134            fillList();
135        } else {
136            showDialog(DIALOG_RESTORE_DEFAULTAPN);
137        }
138    }
139
140    @Override
141    protected void onPause() {
142        super.onPause();
143
144        unregisterReceiver(mMobileStateReceiver);
145    }
146
147    private void fillList() {
148        String where = "numeric=\""
149            + android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")
150            + "\"";
151
152        Cursor cursor = managedQuery(Telephony.Carriers.CONTENT_URI, new String[] {
153                "_id", "name", "apn", "type"}, where,
154                Telephony.Carriers.DEFAULT_SORT_ORDER);
155
156        PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
157        apnList.removeAll();
158
159        ArrayList<Preference> mmsApnList = new ArrayList<Preference>();
160
161        mSelectedKey = getSelectedApnKey();
162        cursor.moveToFirst();
163        while (!cursor.isAfterLast()) {
164            String name = cursor.getString(NAME_INDEX);
165            String apn = cursor.getString(APN_INDEX);
166            String key = cursor.getString(ID_INDEX);
167            String type = cursor.getString(TYPES_INDEX);
168
169            ApnPreference pref = new ApnPreference(this);
170
171            pref.setKey(key);
172            pref.setTitle(name);
173            pref.setSummary(apn);
174            pref.setPersistent(false);
175            pref.setOnPreferenceChangeListener(this);
176
177            boolean selectable = ((type == null) || !type.equals("mms"));
178            pref.setSelectable(selectable);
179            if (selectable) {
180                if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
181                    pref.setChecked();
182                }
183                apnList.addPreference(pref);
184            } else {
185                mmsApnList.add(pref);
186            }
187            cursor.moveToNext();
188        }
189        cursor.close();
190
191        for (Preference preference : mmsApnList) {
192            apnList.addPreference(preference);
193        }
194    }
195
196    @Override
197    public boolean onCreateOptionsMenu(Menu menu) {
198        super.onCreateOptionsMenu(menu);
199        menu.add(0, MENU_NEW, 0,
200                getResources().getString(R.string.menu_new))
201                .setIcon(android.R.drawable.ic_menu_add);
202        menu.add(0, MENU_RESTORE, 0,
203                getResources().getString(R.string.menu_restore))
204                .setIcon(android.R.drawable.ic_menu_upload);
205        return true;
206    }
207
208    @Override
209    public boolean onOptionsItemSelected(MenuItem item) {
210        switch (item.getItemId()) {
211        case MENU_NEW:
212            addNewApn();
213            return true;
214
215        case MENU_RESTORE:
216            restoreDefaultApn();
217            return true;
218        }
219        return super.onOptionsItemSelected(item);
220    }
221
222    private void addNewApn() {
223        startActivity(new Intent(Intent.ACTION_INSERT, Telephony.Carriers.CONTENT_URI));
224    }
225
226    @Override
227    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
228        int pos = Integer.parseInt(preference.getKey());
229        Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
230        startActivity(new Intent(Intent.ACTION_EDIT, url));
231        return true;
232    }
233
234    public boolean onPreferenceChange(Preference preference, Object newValue) {
235        Log.d(TAG, "onPreferenceChange(): Preference - " + preference
236                + ", newValue - " + newValue + ", newValue type - "
237                + newValue.getClass());
238        if (newValue instanceof String) {
239            setSelectedApnKey((String) newValue);
240        }
241
242        return true;
243    }
244
245    private void setSelectedApnKey(String key) {
246        mSelectedKey = key;
247        ContentResolver resolver = getContentResolver();
248
249        ContentValues values = new ContentValues();
250        values.put(APN_ID, mSelectedKey);
251        resolver.update(PREFERAPN_URI, values, null, null);
252    }
253
254    private String getSelectedApnKey() {
255        String key = null;
256
257        Cursor cursor = managedQuery(PREFERAPN_URI, new String[] {"_id"},
258                null, Telephony.Carriers.DEFAULT_SORT_ORDER);
259        if (cursor.getCount() > 0) {
260            cursor.moveToFirst();
261            key = cursor.getString(ID_INDEX);
262        }
263        cursor.close();
264        return key;
265    }
266
267    private boolean restoreDefaultApn() {
268        showDialog(DIALOG_RESTORE_DEFAULTAPN);
269        mRestoreDefaultApnMode = true;
270
271        if (mRestoreApnUiHandler == null) {
272            mRestoreApnUiHandler = new RestoreApnUiHandler();
273        }
274
275        if (mRestoreApnProcessHandler == null) {
276            HandlerThread restoreDefaultApnThread = new HandlerThread(
277                    "Restore default APN Handler: Process Thread");
278            restoreDefaultApnThread.start();
279            mRestoreApnProcessHandler = new RestoreApnProcessHandler(
280                    restoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
281        }
282
283        mRestoreApnProcessHandler
284                .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
285        return true;
286    }
287
288    private class RestoreApnUiHandler extends Handler {
289        @Override
290        public void handleMessage(Message msg) {
291            switch (msg.what) {
292                case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
293                    fillList();
294                    getPreferenceScreen().setEnabled(true);
295                    mRestoreDefaultApnMode = false;
296                    dismissDialog(DIALOG_RESTORE_DEFAULTAPN);
297                    Toast.makeText(
298                        ApnSettings.this,
299                        getResources().getString(
300                                R.string.restore_default_apn_completed),
301                        Toast.LENGTH_LONG).show();
302                    break;
303            }
304        }
305    }
306
307    private class RestoreApnProcessHandler extends Handler {
308        private Handler mRestoreApnUiHandler;
309
310        public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
311            super(looper);
312            this.mRestoreApnUiHandler = restoreApnUiHandler;
313        }
314
315        @Override
316        public void handleMessage(Message msg) {
317            switch (msg.what) {
318                case EVENT_RESTORE_DEFAULTAPN_START:
319                    ContentResolver resolver = getContentResolver();
320                    resolver.delete(DEFAULTAPN_URI, null, null);
321                    mRestoreApnUiHandler
322                        .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE);
323                    break;
324            }
325        }
326    }
327
328    @Override
329    protected Dialog onCreateDialog(int id) {
330        if (id == DIALOG_RESTORE_DEFAULTAPN) {
331            ProgressDialog dialog = new ProgressDialog(this);
332            dialog.setMessage(getResources().getString(R.string.restore_default_apn));
333            dialog.setCancelable(false);
334            return dialog;
335        }
336        return null;
337    }
338
339    @Override
340    protected void onPrepareDialog(int id, Dialog dialog) {
341        if (id == DIALOG_RESTORE_DEFAULTAPN) {
342            getPreferenceScreen().setEnabled(false);
343        }
344    }
345}
346