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