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.emulatorprovisionlib;
18 
19 import android.app.Activity;
20 import android.app.StatusBarManager;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.pm.PackageManager;
24 import android.hardware.input.InputManagerGlobal;
25 import android.hardware.input.KeyboardLayout;
26 import android.location.LocationManager;
27 import android.net.wifi.WifiManager;
28 import android.net.wifi.WifiConfiguration;
29 import android.provider.Settings;
30 import android.os.Bundle;
31 import android.os.Process;
32 import android.os.RemoteException;
33 import android.os.ServiceManager;
34 import android.os.SystemProperties;
35 import android.telephony.TelephonyManager;
36 import android.util.Log;
37 import android.view.InputDevice;
38 
39 import com.android.internal.widget.LockPatternUtils;
40 
41 public abstract class ProvisionActivity extends Activity {
TAG()42     protected abstract String TAG();
43     private StatusBarManager mStatusBarManager;
44 
45     @Override
onCreate(Bundle icicle)46     protected void onCreate(Bundle icicle) {
47         super.onCreate(icicle);
48 
49         if (provisionRequired()) {
50             preProvivion();
51             doProvision();
52             postProvision();
53         } else {
54             Log.w(TAG(), "Already provisioned, remove itself.");
55             removeSelf();
56         }
57 
58         finish();  // terminate the activity.
59     }
60 
preProvivion()61     protected void preProvivion() {
62         final Context appContext = getApplicationContext();
63         mStatusBarManager = appContext.getSystemService(StatusBarManager.class);
64 
65         mStatusBarManager.setDisabledForSetup(true);
66     }
67 
postProvision()68     protected void postProvision() {
69         mStatusBarManager.setDisabledForSetup(false);
70 
71         removeSelf();
72 
73         // Add a persistent setting to allow other apps to know the device has been provisioned.
74         Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);
75         Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
76     }
77 
78     // remove this activity from the package manager.
removeSelf()79     protected void removeSelf() {
80         getPackageManager().setComponentEnabledSetting(
81                 new ComponentName(this, this.getClass()),
82                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
83                 PackageManager.DONT_KILL_APP);
84     }
85 
doProvision()86     protected void doProvision() {
87         provisionWifi("AndroidWifi");
88         provisionKeyboard("qwerty2");
89         provisionDisplay();
90         provisionTelephony();
91         provisionLocation();
92         provisionAdb();
93 
94         Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 1);
95     }
96 
provisionWifi(final String ssid)97     protected void provisionWifi(final String ssid) {
98         Settings.Global.putInt(getContentResolver(), Settings.Global.TETHER_OFFLOAD_DISABLED, 1);
99 
100         final WifiManager mWifiManager = getApplicationContext().getSystemService(WifiManager.class);
101         if (!mWifiManager.setWifiEnabled(true)) {
102             Log.e(TAG(), "Unable to turn on Wi-Fi");
103             return;
104         }
105 
106         final int ADD_NETWORK_FAIL = -1;
107         final String quotedSsid = "\"" + ssid + "\"";
108 
109         final WifiConfiguration config = new WifiConfiguration();
110         config.SSID = quotedSsid;
111         config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
112 
113         final int netId = mWifiManager.addNetwork(config);
114 
115         if (netId == ADD_NETWORK_FAIL || !mWifiManager.enableNetwork(netId, true)) {
116             Log.e(TAG(), "Unable to add Wi-Fi network " + quotedSsid + ".");
117         }
118     }
119 
120     // Set physical keyboard layout based on the system property set by emulator host.
provisionKeyboard(final String deviceName)121     protected void provisionKeyboard(final String deviceName) {
122         Settings.Secure.putInt(getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);
123 
124         final String layoutName = SystemProperties.get("vendor.qemu.keyboard_layout");
125         final InputDevice device = getKeyboardDevice(deviceName);
126         if (device != null && !layoutName.isEmpty()) {
127             setKeyboardLayout(device, layoutName);
128         }
129     }
130 
provisionDisplay()131     protected void provisionDisplay() {
132         Settings.Global.putInt(getContentResolver(), Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 1);
133 
134         final int screen_off_timeout =
135             SystemProperties.getInt("ro.boot.qemu.settings.system.screen_off_timeout", 0);
136         if (screen_off_timeout > 0) {
137             Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, screen_off_timeout);
138             Log.i(TAG(), "Setting system screen_off_timeout to be " + screen_off_timeout + " ms");
139         }
140 
141         (new LockPatternUtils(this)).setLockScreenDisabled(true,
142             android.os.Process.myUserHandle().getIdentifier());
143 
144         final String displaySettingsProp = "ro.boot.qemu.display.settings.xml";
145         final String displaySettingsName = SystemProperties.get(displaySettingsProp);
146         if ("freeform".equals(displaySettingsName)) {
147             Settings.Global.putInt(getContentResolver(), "sf", 1);
148             Settings.Global.putString(getContentResolver(),
149                                       Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, "1");
150             Settings.Global.putString(getContentResolver(),
151                                       Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, "1");
152             Settings.Global.putString(getContentResolver(),
153                                       Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
154                                       "vendor/etc/display_settings_freeform.xml");
155         } else if ("resizable".equals(displaySettingsName)) {
156             // Enable auto rotate for resizable AVD
157             Settings.System.putString(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, "1");
158         } else if (!displaySettingsName.isEmpty()) {
159             Log.e(TAG(), "Unexpected value `" + displaySettingsName + "` in " + displaySettingsProp);
160         }
161         final String autoRotateProp = "ro.boot.qemu.autorotate";
162         final String autoRotateSetting = SystemProperties.get(autoRotateProp);
163         if (!autoRotateSetting.isEmpty()) {
164             Settings.System.putString(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, autoRotateSetting);
165         }
166     }
167 
168     // required for CTS which uses the mock modem
provisionMockModem()169     private void provisionMockModem() {
170         String value = SystemProperties.get("ro.boot.radio.allow_mock_modem");
171         if (!value.isEmpty()) {
172             if (value.equals("1")) {
173                 value = "true";
174             } else if (value.equals("0")) {
175                 value = "false";
176             }
177 
178             SystemProperties.set("persist.radio.allow_mock_modem", value);
179         }
180     }
181 
provisionTelephony()182     protected void provisionTelephony() {
183         // b/193418404
184         // the following blocks, TODO: find out why and fix it. disable this for now.
185         // TelephonyManager mTelephony = getApplicationContext().getSystemService(TelephonyManager.class);
186         // mTelephony.setPreferredNetworkTypeBitmask(TelephonyManager.NETWORK_TYPE_BITMASK_NR);
187 
188         provisionMockModem();
189     }
190 
provisionLocation()191     protected void provisionLocation() {
192         final LocationManager lm = getSystemService(LocationManager.class);
193         lm.setLocationEnabledForUser(true, Process.myUserHandle());
194 
195         // Enable the GPS.
196         // Not needed since this SDK will contain the Settings app.
197         Settings.Secure.putString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
198                 LocationManager.GPS_PROVIDER);
199     }
200 
provisionAdb()201     protected void provisionAdb() {
202         Settings.Global.putInt(getContentResolver(), Settings.Global.ADB_ENABLED, 1);
203         Settings.Global.putInt(getContentResolver(), Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 0);
204     }
205 
getKeyboardDevice(final String keyboardDeviceName)206     protected InputDevice getKeyboardDevice(final String keyboardDeviceName) {
207         final int[] deviceIds = InputDevice.getDeviceIds();
208 
209         for (int deviceId : deviceIds) {
210             InputDevice inputDevice = InputDevice.getDevice(deviceId);
211             if (inputDevice != null
212                     && inputDevice.supportsSource(InputDevice.SOURCE_KEYBOARD)
213                     && inputDevice.getName().equals(keyboardDeviceName)) {
214                 return inputDevice;
215             }
216         }
217 
218         return null;
219     }
220 
setKeyboardLayout(final InputDevice keyboardDevice, final String layoutName)221     protected void setKeyboardLayout(final InputDevice keyboardDevice, final String layoutName) {
222         final InputManagerGlobal im = InputManagerGlobal.getInstance();
223 
224         final KeyboardLayout[] keyboardLayouts =
225                 im.getKeyboardLayoutsForInputDevice(keyboardDevice.getIdentifier());
226 
227         for (KeyboardLayout keyboardLayout : keyboardLayouts) {
228             if (keyboardLayout.getDescriptor().endsWith(layoutName)) {
229                 im.setCurrentKeyboardLayoutForInputDevice(
230                         keyboardDevice.getIdentifier(), keyboardLayout.getDescriptor());
231                 return;
232             }
233         }
234     }
235 
provisionRequired()236     protected boolean provisionRequired() {
237         return (Settings.Global.getInt(getContentResolver(),
238                 Settings.Global.DEVICE_PROVISIONED, 0) != 1) || forceProvision();
239     }
240 
forceProvision()241     protected boolean forceProvision() {
242         return SystemProperties.get("ro.automotive_emulator.provisioning", "").equals("SdkSetup");
243     }
244 }
245