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.deviceinfo;
18 
19 import static android.content.Context.CONNECTIVITY_SERVICE;
20 import static android.content.Context.WIFI_SERVICE;
21 
22 import android.bluetooth.BluetoothAdapter;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.res.Resources;
28 import android.net.ConnectivityManager;
29 import android.net.wifi.WifiInfo;
30 import android.net.wifi.WifiManager;
31 import android.os.Build;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.os.SystemClock;
36 import android.os.SystemProperties;
37 import android.os.UserManager;
38 import android.support.v7.preference.Preference;
39 import android.text.TextUtils;
40 
41 import com.android.internal.logging.MetricsProto.MetricsEvent;
42 import com.android.internal.util.ArrayUtils;
43 import com.android.settings.R;
44 import com.android.settings.SettingsPreferenceFragment;
45 import com.android.settings.Utils;
46 
47 import java.lang.ref.WeakReference;
48 
49 /**
50  * Display the following information
51  * # Battery Strength  : TODO
52  * # Uptime
53  * # Awake Time
54  * # XMPP/buzz/tickle status : TODO
55  *
56  */
57 public class Status extends SettingsPreferenceFragment {
58 
59     private static final String KEY_BATTERY_STATUS = "battery_status";
60     private static final String KEY_BATTERY_LEVEL = "battery_level";
61     private static final String KEY_IP_ADDRESS = "wifi_ip_address";
62     private static final String KEY_WIFI_MAC_ADDRESS = "wifi_mac_address";
63     private static final String KEY_BT_ADDRESS = "bt_address";
64     private static final String KEY_SERIAL_NUMBER = "serial_number";
65     private static final String KEY_WIMAX_MAC_ADDRESS = "wimax_mac_address";
66     private static final String KEY_SIM_STATUS = "sim_status";
67     private static final String KEY_IMEI_INFO = "imei_info";
68 
69     // Broadcasts to listen to for connectivity changes.
70     private static final String[] CONNECTIVITY_INTENTS = {
71             BluetoothAdapter.ACTION_STATE_CHANGED,
72             ConnectivityManager.CONNECTIVITY_ACTION,
73             WifiManager.LINK_CONFIGURATION_CHANGED_ACTION,
74             WifiManager.NETWORK_STATE_CHANGED_ACTION,
75     };
76 
77     private static final int EVENT_UPDATE_STATS = 500;
78 
79     private static final int EVENT_UPDATE_CONNECTIVITY = 600;
80 
81     private ConnectivityManager mCM;
82     private WifiManager mWifiManager;
83 
84     private Resources mRes;
85 
86     private String mUnknown;
87     private String mUnavailable;
88 
89     private Preference mUptime;
90     private Preference mBatteryStatus;
91     private Preference mBatteryLevel;
92     private Preference mBtAddress;
93     private Preference mIpAddress;
94     private Preference mWifiMacAddress;
95     private Preference mWimaxMacAddress;
96 
97     private Handler mHandler;
98 
99     private static class MyHandler extends Handler {
100         private WeakReference<Status> mStatus;
101 
MyHandler(Status activity)102         public MyHandler(Status activity) {
103             mStatus = new WeakReference<Status>(activity);
104         }
105 
106         @Override
handleMessage(Message msg)107         public void handleMessage(Message msg) {
108             Status status = mStatus.get();
109             if (status == null) {
110                 return;
111             }
112 
113             switch (msg.what) {
114                 case EVENT_UPDATE_STATS:
115                     status.updateTimes();
116                     sendEmptyMessageDelayed(EVENT_UPDATE_STATS, 1000);
117                     break;
118 
119                 case EVENT_UPDATE_CONNECTIVITY:
120                     status.updateConnectivity();
121                     break;
122             }
123         }
124     }
125 
126     private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
127 
128         @Override
129         public void onReceive(Context context, Intent intent) {
130             String action = intent.getAction();
131             if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
132                 mBatteryLevel.setSummary(Utils.getBatteryPercentage(intent));
133                 mBatteryStatus.setSummary(Utils.getBatteryStatus(getResources(), intent));
134             }
135         }
136     };
137 
138     private IntentFilter mConnectivityIntentFilter;
139     private final BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
140         @Override
141         public void onReceive(Context context, Intent intent) {
142             String action = intent.getAction();
143             if (ArrayUtils.contains(CONNECTIVITY_INTENTS, action)) {
144                 mHandler.sendEmptyMessage(EVENT_UPDATE_CONNECTIVITY);
145             }
146         }
147     };
148 
hasBluetooth()149     private boolean hasBluetooth() {
150         return BluetoothAdapter.getDefaultAdapter() != null;
151     }
152 
hasWimax()153     private boolean hasWimax() {
154         return  mCM.getNetworkInfo(ConnectivityManager.TYPE_WIMAX) != null;
155     }
156 
157     @Override
onCreate(Bundle icicle)158     public void onCreate(Bundle icicle) {
159         super.onCreate(icicle);
160 
161         mHandler = new MyHandler(this);
162 
163         mCM = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
164         mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
165 
166         addPreferencesFromResource(R.xml.device_info_status);
167         mBatteryLevel = findPreference(KEY_BATTERY_LEVEL);
168         mBatteryStatus = findPreference(KEY_BATTERY_STATUS);
169         mBtAddress = findPreference(KEY_BT_ADDRESS);
170         mWifiMacAddress = findPreference(KEY_WIFI_MAC_ADDRESS);
171         mWimaxMacAddress = findPreference(KEY_WIMAX_MAC_ADDRESS);
172         mIpAddress = findPreference(KEY_IP_ADDRESS);
173 
174         mRes = getResources();
175         mUnknown = mRes.getString(R.string.device_info_default);
176         mUnavailable = mRes.getString(R.string.status_unavailable);
177 
178         // Note - missing in zaku build, be careful later...
179         mUptime = findPreference("up_time");
180 
181         if (!hasBluetooth()) {
182             getPreferenceScreen().removePreference(mBtAddress);
183             mBtAddress = null;
184         }
185 
186         if (!hasWimax()) {
187             getPreferenceScreen().removePreference(mWimaxMacAddress);
188             mWimaxMacAddress = null;
189         }
190 
191         mConnectivityIntentFilter = new IntentFilter();
192         for (String intent: CONNECTIVITY_INTENTS) {
193              mConnectivityIntentFilter.addAction(intent);
194         }
195 
196         updateConnectivity();
197 
198         String serial = Build.SERIAL;
199         if (serial != null && !serial.equals("")) {
200             setSummaryText(KEY_SERIAL_NUMBER, serial);
201         } else {
202             removePreferenceFromScreen(KEY_SERIAL_NUMBER);
203         }
204 
205         // Remove SimStatus and Imei for Secondary user as it access Phone b/19165700
206         // Also remove on Wi-Fi only devices.
207         //TODO: the bug above will surface in split system user mode.
208         if (!UserManager.get(getContext()).isAdminUser()
209                 || Utils.isWifiOnly(getContext())) {
210             removePreferenceFromScreen(KEY_SIM_STATUS);
211             removePreferenceFromScreen(KEY_IMEI_INFO);
212         }
213     }
214 
215     @Override
getMetricsCategory()216     protected int getMetricsCategory() {
217         return MetricsEvent.DEVICEINFO_STATUS;
218     }
219 
220     @Override
onResume()221     public void onResume() {
222         super.onResume();
223         getContext().registerReceiver(mConnectivityReceiver, mConnectivityIntentFilter,
224                          android.Manifest.permission.CHANGE_NETWORK_STATE, null);
225         getContext().registerReceiver(mBatteryInfoReceiver,
226                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
227         mHandler.sendEmptyMessage(EVENT_UPDATE_STATS);
228     }
229 
230     @Override
onPause()231     public void onPause() {
232         super.onPause();
233 
234         getContext().unregisterReceiver(mBatteryInfoReceiver);
235         getContext().unregisterReceiver(mConnectivityReceiver);
236         mHandler.removeMessages(EVENT_UPDATE_STATS);
237     }
238 
239     /**
240      * Removes the specified preference, if it exists.
241      * @param key the key for the Preference item
242      */
removePreferenceFromScreen(String key)243     private void removePreferenceFromScreen(String key) {
244         Preference pref = findPreference(key);
245         if (pref != null) {
246             getPreferenceScreen().removePreference(pref);
247         }
248     }
249 
250     /**
251      * @param preference The key for the Preference item
252      * @param property The system property to fetch
253      * @param alt The default value, if the property doesn't exist
254      */
setSummary(String preference, String property, String alt)255     private void setSummary(String preference, String property, String alt) {
256         try {
257             findPreference(preference).setSummary(
258                     SystemProperties.get(property, alt));
259         } catch (RuntimeException e) {
260 
261         }
262     }
263 
setSummaryText(String preference, String text)264     private void setSummaryText(String preference, String text) {
265             if (TextUtils.isEmpty(text)) {
266                text = mUnknown;
267              }
268              // some preferences may be missing
269              if (findPreference(preference) != null) {
270                  findPreference(preference).setSummary(text);
271              }
272     }
273 
setWimaxStatus()274     private void setWimaxStatus() {
275         if (mWimaxMacAddress != null) {
276             String macAddress = SystemProperties.get("net.wimax.mac.address", mUnavailable);
277             mWimaxMacAddress.setSummary(macAddress);
278         }
279     }
280 
setWifiStatus()281     private void setWifiStatus() {
282         WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
283         String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
284         mWifiMacAddress.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress : mUnavailable);
285     }
286 
setIpAddressStatus()287     private void setIpAddressStatus() {
288         String ipAddress = Utils.getDefaultIpAddresses(this.mCM);
289         if (ipAddress != null) {
290             mIpAddress.setSummary(ipAddress);
291         } else {
292             mIpAddress.setSummary(mUnavailable);
293         }
294     }
295 
setBtStatus()296     private void setBtStatus() {
297         BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
298         if (bluetooth != null && mBtAddress != null) {
299             String address = bluetooth.isEnabled() ? bluetooth.getAddress() : null;
300             if (!TextUtils.isEmpty(address)) {
301                // Convert the address to lowercase for consistency with the wifi MAC address.
302                 mBtAddress.setSummary(address.toLowerCase());
303             } else {
304                 mBtAddress.setSummary(mUnavailable);
305             }
306         }
307     }
308 
updateConnectivity()309     void updateConnectivity() {
310         setWimaxStatus();
311         setWifiStatus();
312         setBtStatus();
313         setIpAddressStatus();
314     }
315 
updateTimes()316     void updateTimes() {
317         long at = SystemClock.uptimeMillis() / 1000;
318         long ut = SystemClock.elapsedRealtime() / 1000;
319 
320         if (ut == 0) {
321             ut = 1;
322         }
323 
324         mUptime.setSummary(convert(ut));
325     }
326 
pad(int n)327     private String pad(int n) {
328         if (n >= 10) {
329             return String.valueOf(n);
330         } else {
331             return "0" + String.valueOf(n);
332         }
333     }
334 
convert(long t)335     private String convert(long t) {
336         int s = (int)(t % 60);
337         int m = (int)((t / 60) % 60);
338         int h = (int)((t / 3600));
339 
340         return h + ":" + pad(m) + ":" + pad(s);
341     }
342 }
343