1/*
2 * Copyright (C) 2007 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.wifi;
18
19import com.android.settings.R;
20
21import android.content.ContentResolver;
22import android.net.wifi.WifiInfo;
23import android.net.wifi.WifiManager;
24import android.os.Bundle;
25import android.preference.CheckBoxPreference;
26import android.preference.EditTextPreference;
27import android.preference.ListPreference;
28import android.preference.Preference;
29import android.preference.PreferenceActivity;
30import android.provider.Settings;
31import android.provider.Settings.System;
32import android.text.TextUtils;
33import android.view.KeyEvent;
34import android.view.Menu;
35import android.view.MenuItem;
36import android.widget.Toast;
37import android.os.SystemProperties;
38
39public class AdvancedSettings extends PreferenceActivity
40        implements Preference.OnPreferenceChangeListener {
41
42    private static final String KEY_MAC_ADDRESS = "mac_address";
43    private static final String KEY_USE_STATIC_IP = "use_static_ip";
44    private static final String KEY_NUM_CHANNELS = "num_channels";
45    private static final String KEY_SLEEP_POLICY = "sleep_policy";
46
47    private String[] mSettingNames = {
48            System.WIFI_STATIC_IP, System.WIFI_STATIC_GATEWAY, System.WIFI_STATIC_NETMASK,
49            System.WIFI_STATIC_DNS1, System.WIFI_STATIC_DNS2
50    };
51
52    private String[] mPreferenceKeys = {
53            "ip_address", "gateway", "netmask", "dns1", "dns2"
54    };
55
56    private CheckBoxPreference mUseStaticIpCheckBox;
57
58    private static final int MENU_ITEM_SAVE = Menu.FIRST;
59    private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1;
60
61    //Tracks ro.debuggable (1 on userdebug builds)
62    private static int DEBUGGABLE;
63
64    @Override
65    protected void onCreate(Bundle savedInstanceState) {
66        super.onCreate(savedInstanceState);
67
68        addPreferencesFromResource(R.xml.wifi_advanced_settings);
69
70        mUseStaticIpCheckBox = (CheckBoxPreference) findPreference(KEY_USE_STATIC_IP);
71        mUseStaticIpCheckBox.setOnPreferenceChangeListener(this);
72
73        for (int i = 0; i < mPreferenceKeys.length; i++) {
74            Preference preference = findPreference(mPreferenceKeys[i]);
75            preference.setOnPreferenceChangeListener(this);
76        }
77
78        DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0);
79
80        /**
81         * Remove user control of regulatory domain
82         * channel count settings in non userdebug builds
83         */
84        if (DEBUGGABLE == 1) {
85            /*
86             * Fix the Run-time IllegalStateException that ListPreference requires an entries
87             * array and an entryValues array, this exception occurs when user open/close the
88             * slider in the Regulatory domain dialog.
89             */
90            initNumChannelsPreference();
91        } else {
92            Preference chanPref = findPreference(KEY_NUM_CHANNELS);
93            if (chanPref != null) {
94              getPreferenceScreen().removePreference(chanPref);
95            }
96        }
97    }
98
99    @Override
100    protected void onResume() {
101        super.onResume();
102
103        updateUi();
104        /**
105         * Remove user control of regulatory domain
106         * channel count settings in non userdebug builds
107         */
108        if (DEBUGGABLE == 1) {
109            initNumChannelsPreference();
110        }
111        initSleepPolicyPreference();
112        refreshMacAddress();
113    }
114
115    private void initNumChannelsPreference() {
116        ListPreference pref = (ListPreference) findPreference(KEY_NUM_CHANNELS);
117        pref.setOnPreferenceChangeListener(this);
118
119        WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
120        /*
121         * Generate the list of valid channel counts to show in the ListPreference.
122         * The values are numerical, so the only text to be localized is the
123         * "channel_word" resource.
124         */
125        int[] validChannelCounts = wifiManager.getValidChannelCounts();
126        if (validChannelCounts == null) {
127            Toast.makeText(this, R.string.wifi_setting_num_channels_error,
128                           Toast.LENGTH_SHORT).show();
129            pref.setEnabled(false);
130            return;
131        }
132        String[] entries = new String[validChannelCounts.length];
133        String[] entryValues = new String[validChannelCounts.length];
134
135        for (int i = 0; i < validChannelCounts.length; i++) {
136            entryValues[i] = String.valueOf(validChannelCounts[i]);
137            entries[i] = getString(R.string.wifi_setting_num_channels_channel_phrase,
138                                   validChannelCounts[i]);
139        }
140        pref.setEntries(entries);
141        pref.setEntryValues(entryValues);
142        pref.setEnabled(true);
143        int numChannels = wifiManager.getNumAllowedChannels();
144        if (numChannels >= 0) {
145            pref.setValue(String.valueOf(numChannels));
146        }
147    }
148
149    private void initSleepPolicyPreference() {
150        ListPreference pref = (ListPreference) findPreference(KEY_SLEEP_POLICY);
151        pref.setOnPreferenceChangeListener(this);
152        int value = Settings.System.getInt(getContentResolver(),
153                Settings.System.WIFI_SLEEP_POLICY,Settings. System.WIFI_SLEEP_POLICY_DEFAULT);
154        pref.setValue(String.valueOf(value));
155    }
156
157    @Override
158    public boolean onKeyDown(int keyCode, KeyEvent event) {
159
160        if (keyCode == KeyEvent.KEYCODE_BACK) {
161            updateSettingsProvider();
162        }
163
164        return super.onKeyDown(keyCode, event);
165    }
166
167    public boolean onPreferenceChange(Preference preference, Object newValue) {
168        String key = preference.getKey();
169        if (key == null) return true;
170
171        if (key.equals(KEY_NUM_CHANNELS)) {
172            try {
173                int numChannels = Integer.parseInt((String) newValue);
174                WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
175                if (!wifiManager.setNumAllowedChannels(numChannels, true)) {
176                    Toast.makeText(this, R.string.wifi_setting_num_channels_error,
177                            Toast.LENGTH_SHORT).show();
178                }
179            } catch (NumberFormatException e) {
180                Toast.makeText(this, R.string.wifi_setting_num_channels_error,
181                        Toast.LENGTH_SHORT).show();
182                return false;
183            }
184
185        } else if (key.equals(KEY_SLEEP_POLICY)) {
186            try {
187                Settings.System.putInt(getContentResolver(),
188                        Settings.System.WIFI_SLEEP_POLICY, Integer.parseInt(((String) newValue)));
189            } catch (NumberFormatException e) {
190                Toast.makeText(this, R.string.wifi_setting_sleep_policy_error,
191                        Toast.LENGTH_SHORT).show();
192                return false;
193            }
194
195        } else if (key.equals(KEY_USE_STATIC_IP)) {
196            boolean value = ((Boolean) newValue).booleanValue();
197
198            try {
199                Settings.System.putInt(getContentResolver(),
200                        Settings.System.WIFI_USE_STATIC_IP, value ? 1 : 0);
201            } catch (NumberFormatException e) {
202                return false;
203            }
204        } else {
205            String value = (String) newValue;
206
207            if (!isIpAddress(value)) {
208                Toast.makeText(this, R.string.wifi_ip_settings_invalid_ip, Toast.LENGTH_LONG).show();
209                return false;
210            }
211
212            preference.setSummary(value);
213            for (int i = 0; i < mSettingNames.length; i++) {
214                if (key.equals(mPreferenceKeys[i])) {
215                    Settings.System.putString(getContentResolver(), mSettingNames[i], value);
216                    break;
217                }
218            }
219        }
220
221        return true;
222    }
223
224    private boolean isIpAddress(String value) {
225
226        int start = 0;
227        int end = value.indexOf('.');
228        int numBlocks = 0;
229
230        while (start < value.length()) {
231
232            if (end == -1) {
233                end = value.length();
234            }
235
236            try {
237                int block = Integer.parseInt(value.substring(start, end));
238                if ((block > 255) || (block < 0)) {
239                    return false;
240                }
241            } catch (NumberFormatException e) {
242                return false;
243            }
244
245            numBlocks++;
246
247            start = end + 1;
248            end = value.indexOf('.', start);
249        }
250
251        return numBlocks == 4;
252    }
253
254    @Override
255    public boolean onCreateOptionsMenu(Menu menu) {
256
257        menu.add(0, MENU_ITEM_SAVE, 0, R.string.wifi_ip_settings_menu_save)
258                .setIcon(android.R.drawable.ic_menu_save);
259
260        menu.add(0, MENU_ITEM_CANCEL, 0, R.string.wifi_ip_settings_menu_cancel)
261                .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
262
263        return super.onCreateOptionsMenu(menu);
264    }
265
266    @Override
267    public boolean onOptionsItemSelected(MenuItem item) {
268
269        switch (item.getItemId()) {
270
271            case MENU_ITEM_SAVE:
272                updateSettingsProvider();
273                finish();
274                return true;
275
276            case MENU_ITEM_CANCEL:
277                finish();
278                return true;
279        }
280
281        return super.onOptionsItemSelected(item);
282    }
283
284    private void updateUi() {
285        ContentResolver contentResolver = getContentResolver();
286
287        mUseStaticIpCheckBox.setChecked(System.getInt(contentResolver,
288                System.WIFI_USE_STATIC_IP, 0) != 0);
289
290        for (int i = 0; i < mSettingNames.length; i++) {
291            EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
292            String settingValue = System.getString(contentResolver, mSettingNames[i]);
293            preference.setText(settingValue);
294            preference.setSummary(settingValue);
295        }
296    }
297
298    private void updateSettingsProvider() {
299        ContentResolver contentResolver = getContentResolver();
300
301        System.putInt(contentResolver, System.WIFI_USE_STATIC_IP,
302                mUseStaticIpCheckBox.isChecked() ? 1 : 0);
303
304        for (int i = 0; i < mSettingNames.length; i++) {
305            EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
306            System.putString(contentResolver, mSettingNames[i], preference.getText());
307        }
308    }
309
310    private void refreshMacAddress() {
311        WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
312        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
313
314        Preference wifiMacAddressPref = findPreference(KEY_MAC_ADDRESS);
315        String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
316        wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress
317                : getString(R.string.status_unavailable));
318    }
319
320}
321