Add a GSI/DSU Loader to the developer option.
The Generic System Image (GSI) is a pure Android implementation with unmodified Android Open Source Project (AOSP) code. The Dynamic System Updates (DSU) is a Android Q feature that can download a system image and boot into it without the factory rom being corrupted. This CL adds a DSU Loader which is a friendly front-end that offers developers the ability to boot into GSI with one-click. The DSU loader also offers the flexibility to overwrite the default setting and load OEMs owned images. Bug: 140090894 Test: click settings->developer option->debug::DSU Loader make -j32 RunSettingsRoboTests Change-Id: Ia2a1b69b52047dd841dedf7f07b07f7ad3e65d46
This commit is contained in:
@@ -98,6 +98,7 @@
|
|||||||
<uses-permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS" />
|
<uses-permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
|
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
|
||||||
|
<uses-permission android:name="android.permission.INSTALL_DYNAMIC_SYSTEM" />
|
||||||
|
|
||||||
<application android:label="@string/settings_label"
|
<application android:label="@string/settings_label"
|
||||||
android:icon="@drawable/ic_launcher_settings"
|
android:icon="@drawable/ic_launcher_settings"
|
||||||
@@ -1945,6 +1946,10 @@
|
|||||||
android:label="@string/select_application"
|
android:label="@string/select_application"
|
||||||
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog" />
|
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog" />
|
||||||
|
|
||||||
|
<activity android:name=".development.DSULoader"
|
||||||
|
android:label="Select DSU Package"
|
||||||
|
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog" />
|
||||||
|
|
||||||
<activity android:name="Settings$WebViewAppPickerActivity"
|
<activity android:name="Settings$WebViewAppPickerActivity"
|
||||||
android:label="@string/select_webview_provider_dialog_title" />
|
android:label="@string/select_webview_provider_dialog_title" />
|
||||||
|
|
||||||
|
@@ -11314,4 +11314,11 @@
|
|||||||
<!-- Developer Settings: Search keywords for the Profile HWUI rendering. [CHAR_LIMIT=NONE] -->
|
<!-- Developer Settings: Search keywords for the Profile HWUI rendering. [CHAR_LIMIT=NONE] -->
|
||||||
<string name="track_frame_time_keywords">GPU</string>
|
<string name="track_frame_time_keywords">GPU</string>
|
||||||
|
|
||||||
|
<!-- DSU Loader. Do not translate. -->
|
||||||
|
<string name="dsu_loader_title" translatable="false">DSU Loader</string>
|
||||||
|
<!-- DSU Loader Description. Do not translate. -->
|
||||||
|
<string name="dsu_loader_description" translatable="false">Load a Dyanmic System Update Image</string>
|
||||||
|
<!-- DSU Loader Loading. Do not translate. -->
|
||||||
|
<string name="dsu_loader_loading" translatable="false">Loading...</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -108,6 +108,9 @@
|
|||||||
android:title="@string/ota_disable_automatic_update"
|
android:title="@string/ota_disable_automatic_update"
|
||||||
android:summary="@string/ota_disable_automatic_update_summary" />
|
android:summary="@string/ota_disable_automatic_update_summary" />
|
||||||
|
|
||||||
|
<Preference android:key="dsu_loader"
|
||||||
|
android:title="@string/dsu_loader_title" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="demo_mode"
|
android:key="demo_mode"
|
||||||
android:title="@string/demo_mode">
|
android:title="@string/demo_mode">
|
||||||
|
368
src/com/android/settings/development/DSULoader.java
Normal file
368
src/com/android/settings/development/DSULoader.java
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.SystemProperties;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DSU Loader is a front-end that offers developers the ability to boot into GSI with one-click. It
|
||||||
|
* also offers the flexibility to overwrite the default setting and load OEMs owned images.
|
||||||
|
*/
|
||||||
|
public class DSULoader extends ListActivity {
|
||||||
|
public static final String PROPERTY_KEY_FEATURE_FLAG =
|
||||||
|
"persist.sys.fflag.override.settings_dynamic_system";
|
||||||
|
private static final int Q_VNDK_BASE = 28;
|
||||||
|
private static final int Q_OS_BASE = 10;
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
private static final String TAG = "DSULOADER";
|
||||||
|
private static final String PROPERTY_KEY_CPU = "ro.product.cpu.abi";
|
||||||
|
private static final String PROPERTY_KEY_OS = "ro.system.build.version.release";
|
||||||
|
private static final String PROPERTY_KEY_VNDK = "ro.vndk.version";
|
||||||
|
private static final String PROPERTY_KEY_LIST = "ro.vendor.dsu.list";
|
||||||
|
private static final String DSU_LIST =
|
||||||
|
"https://dl.google.com/developers/android/gsi/gsi-src.json";
|
||||||
|
|
||||||
|
private static final int TIMEOUT_MS = 10 * 1000;
|
||||||
|
private List<Object> mDSUList = new ArrayList<Object>();
|
||||||
|
private ArrayAdapter<Object> mAdapter;
|
||||||
|
|
||||||
|
private static String readAll(InputStream in) throws IOException {
|
||||||
|
int n;
|
||||||
|
StringBuilder list = new StringBuilder();
|
||||||
|
byte[] bytes = new byte[4096];
|
||||||
|
while ((n = in.read(bytes, 0, 4096)) != -1) {
|
||||||
|
list.append(new String(Arrays.copyOf(bytes, n)));
|
||||||
|
}
|
||||||
|
return list.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readAll(URL url) throws IOException {
|
||||||
|
InputStream in = null;
|
||||||
|
HttpsURLConnection connection = null;
|
||||||
|
Slog.i(TAG, "fetch " + url.toString());
|
||||||
|
try {
|
||||||
|
connection = (HttpsURLConnection) url.openConnection();
|
||||||
|
connection.setReadTimeout(TIMEOUT_MS);
|
||||||
|
connection.setConnectTimeout(TIMEOUT_MS);
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.connect();
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (connection.getResponseCode() != HttpsURLConnection.HTTP_OK) {
|
||||||
|
throw new IOException("HTTP error code: " + responseCode);
|
||||||
|
}
|
||||||
|
in = new BufferedInputStream(connection.getInputStream());
|
||||||
|
return readAll(in);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (in != null) {
|
||||||
|
in.close();
|
||||||
|
in = null;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fetcher fetches mDSUList in backgroud
|
||||||
|
private class Fetcher implements Runnable {
|
||||||
|
private URL mDsuList;
|
||||||
|
|
||||||
|
Fetcher(URL dsuList) {
|
||||||
|
mDsuList = dsuList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetch(URL url) throws IOException, JSONException, MalformedURLException {
|
||||||
|
String content = readAll(url);
|
||||||
|
JSONObject jsn = new JSONObject(content);
|
||||||
|
// The include primitive is like below
|
||||||
|
// "include": [
|
||||||
|
// "https:/...json",
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
if (jsn.has("include")) {
|
||||||
|
JSONArray include = jsn.getJSONArray("include");
|
||||||
|
int len = include.length();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (include.isNull(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fetch(new URL(include.getString(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// "images":[
|
||||||
|
// {
|
||||||
|
// "name":"...",
|
||||||
|
// "os_version":"10",
|
||||||
|
// "cpu_abi":"...",
|
||||||
|
// "details":"...",
|
||||||
|
// "vndk":[],
|
||||||
|
// "spl":"...",
|
||||||
|
// "pubkey":"",
|
||||||
|
// "uri":"https://...zip"
|
||||||
|
// },
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
|
if (jsn.has("images")) {
|
||||||
|
JSONArray images = jsn.getJSONArray("images");
|
||||||
|
int len = images.length();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
DSUPackage dsu = new DSUPackage(images.getJSONObject(i));
|
||||||
|
if (dsu.isSupported()) {
|
||||||
|
mDSUList.add(dsu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
fetch(mDsuList);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Slog.e(TAG, e.toString());
|
||||||
|
mDSUList.add(0, "Network Error");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.e(TAG, e.toString());
|
||||||
|
mDSUList.add(0, "Metadata Error");
|
||||||
|
}
|
||||||
|
if (mDSUList.size() == 0) {
|
||||||
|
mDSUList.add(0, "No DSU available for this device");
|
||||||
|
}
|
||||||
|
runOnUiThread(
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
mAdapter.clear();
|
||||||
|
mAdapter.addAll(mDSUList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DSUPackage {
|
||||||
|
private static final String NAME = "name";
|
||||||
|
private static final String DETAILS = "details";
|
||||||
|
private static final String CPU_ABI = "cpu_abi";
|
||||||
|
private static final String URI = "uri";
|
||||||
|
private static final String OS_VERSION = "os_version";
|
||||||
|
private static final String VNDK = "vndk";
|
||||||
|
private static final String PUBKEY = "pubkey";
|
||||||
|
|
||||||
|
String mName = null;
|
||||||
|
String mDetails = null;
|
||||||
|
String mCpuAbi = null;
|
||||||
|
int mOsVersion = -1;
|
||||||
|
int[] mVndk = null;
|
||||||
|
String mPubKey = "";
|
||||||
|
URL mUri;
|
||||||
|
|
||||||
|
DSUPackage(JSONObject jsn) throws JSONException, MalformedURLException {
|
||||||
|
Slog.i(TAG, "DSUPackage: " + jsn.toString());
|
||||||
|
mName = jsn.getString(NAME);
|
||||||
|
mDetails = jsn.getString(DETAILS);
|
||||||
|
mCpuAbi = jsn.getString(CPU_ABI);
|
||||||
|
mUri = new URL(jsn.getString(URI));
|
||||||
|
if (jsn.has(OS_VERSION)) {
|
||||||
|
mOsVersion = dessertNumber(jsn.getString(OS_VERSION), Q_OS_BASE);
|
||||||
|
}
|
||||||
|
if (jsn.has(VNDK)) {
|
||||||
|
JSONArray vndks = jsn.getJSONArray(VNDK);
|
||||||
|
mVndk = new int[vndks.length()];
|
||||||
|
for (int i = 0; i < vndks.length(); i++) {
|
||||||
|
mVndk[i] = vndks.getInt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jsn.has(PUBKEY)) {
|
||||||
|
mPubKey = jsn.getString(PUBKEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dessertNumber(String s, int base) {
|
||||||
|
if (s == null || s.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (Character.isDigit(s.charAt(0))) {
|
||||||
|
return Integer.parseInt(s);
|
||||||
|
} else {
|
||||||
|
s = s.toUpperCase();
|
||||||
|
return ((int) s.charAt(0) - (int) 'Q') + base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getDeviceVndk() {
|
||||||
|
if (DEBUG) {
|
||||||
|
return Q_VNDK_BASE;
|
||||||
|
}
|
||||||
|
return dessertNumber(SystemProperties.get(PROPERTY_KEY_VNDK), Q_VNDK_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getDeviceOs() {
|
||||||
|
if (DEBUG) {
|
||||||
|
return Q_OS_BASE;
|
||||||
|
}
|
||||||
|
return dessertNumber(SystemProperties.get(PROPERTY_KEY_OS), Q_OS_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDeviceCpu() {
|
||||||
|
String cpu = SystemProperties.get(PROPERTY_KEY_CPU);
|
||||||
|
cpu = cpu.toLowerCase();
|
||||||
|
if (cpu.startsWith("aarch64")) {
|
||||||
|
cpu = "arm64-v8a";
|
||||||
|
}
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSupported() {
|
||||||
|
boolean supported = true;
|
||||||
|
String cpu = getDeviceCpu();
|
||||||
|
if (!mCpuAbi.equals(cpu)) {
|
||||||
|
Slog.i(TAG, mCpuAbi + " != " + cpu);
|
||||||
|
supported = false;
|
||||||
|
}
|
||||||
|
if (mOsVersion > 0) {
|
||||||
|
int os = getDeviceOs();
|
||||||
|
if (os < 0) {
|
||||||
|
Slog.i(TAG, "Failed to getDeviceOs");
|
||||||
|
supported = false;
|
||||||
|
} else if (mOsVersion < os) {
|
||||||
|
Slog.i(TAG, mOsVersion + " < " + os);
|
||||||
|
supported = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mVndk != null) {
|
||||||
|
int vndk = getDeviceVndk();
|
||||||
|
if (vndk < 0) {
|
||||||
|
Slog.i(TAG, "Failed to getDeviceVndk");
|
||||||
|
supported = false;
|
||||||
|
} else {
|
||||||
|
boolean found_vndk = false;
|
||||||
|
for (int i = 0; i < mVndk.length; i++) {
|
||||||
|
if (mVndk[i] == vndk) {
|
||||||
|
found_vndk = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found_vndk) {
|
||||||
|
Slog.i(TAG, "vndk:" + vndk + " not found");
|
||||||
|
supported = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Slog.i(TAG, mName + " isSupported " + supported);
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
SystemProperties.set(PROPERTY_KEY_FEATURE_FLAG, "1");
|
||||||
|
String dsuList = SystemProperties.get(PROPERTY_KEY_LIST);
|
||||||
|
Slog.e(TAG, "Try to get DSU list from: " + PROPERTY_KEY_LIST);
|
||||||
|
if (dsuList == null || dsuList.isEmpty()) {
|
||||||
|
dsuList = DSU_LIST;
|
||||||
|
}
|
||||||
|
Slog.e(TAG, "DSU list: " + dsuList);
|
||||||
|
URL url = null;
|
||||||
|
try {
|
||||||
|
url = new URL(dsuList);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
Slog.e(TAG, e.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new Thread(new Fetcher(url)).start();
|
||||||
|
mAdapter = new DSUPackageListAdapter(this);
|
||||||
|
setListAdapter(mAdapter);
|
||||||
|
mAdapter.add(getResources().getString(R.string.dsu_loader_loading));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
|
Object selected = mAdapter.getItem(position);
|
||||||
|
if (selected instanceof DSUPackage) {
|
||||||
|
DSUPackage dsu = (DSUPackage) selected;
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setClassName(
|
||||||
|
"com.android.dynsystem", "com.android.dynsystem.VerificationActivity");
|
||||||
|
intent.setData(Uri.parse(dsu.mUri.toString()));
|
||||||
|
intent.putExtra("KEY_PUBKEY", dsu.mPubKey);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DSUPackageListAdapter extends ArrayAdapter<Object> {
|
||||||
|
private final LayoutInflater mInflater;
|
||||||
|
|
||||||
|
DSUPackageListAdapter(Context context) {
|
||||||
|
super(context, 0);
|
||||||
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView);
|
||||||
|
convertView = holder.rootView;
|
||||||
|
Object item = getItem(position);
|
||||||
|
if (item instanceof DSUPackage) {
|
||||||
|
DSUPackage dsu = (DSUPackage) item;
|
||||||
|
holder.appName.setText(dsu.mName);
|
||||||
|
holder.summary.setText(dsu.mDetails);
|
||||||
|
} else {
|
||||||
|
String msg = (String) item;
|
||||||
|
holder.summary.setText(msg);
|
||||||
|
}
|
||||||
|
holder.appIcon.setImageDrawable(null);
|
||||||
|
holder.disabled.setVisibility(View.GONE);
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -430,6 +430,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
|||||||
controllers.add(new WebViewAppPreferenceController(context));
|
controllers.add(new WebViewAppPreferenceController(context));
|
||||||
controllers.add(new CoolColorTemperaturePreferenceController(context));
|
controllers.add(new CoolColorTemperaturePreferenceController(context));
|
||||||
controllers.add(new DisableAutomaticUpdatesPreferenceController(context));
|
controllers.add(new DisableAutomaticUpdatesPreferenceController(context));
|
||||||
|
controllers.add(new SelectDSUPreferenceController(context));
|
||||||
controllers.add(new AdbPreferenceController(context, fragment));
|
controllers.add(new AdbPreferenceController(context, fragment));
|
||||||
controllers.add(new ClearAdbKeysPreferenceController(context, fragment));
|
controllers.add(new ClearAdbKeysPreferenceController(context, fragment));
|
||||||
controllers.add(new LocalTerminalPreferenceController(context));
|
controllers.add(new LocalTerminalPreferenceController(context));
|
||||||
|
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
|
||||||
|
|
||||||
|
class SelectDSUPreferenceController extends DeveloperOptionsPreferenceController {
|
||||||
|
|
||||||
|
private static final String DSU_LOADER_KEY = "dsu_loader";
|
||||||
|
|
||||||
|
SelectDSUPreferenceController(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return DSU_LOADER_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||||
|
if (DSU_LOADER_KEY.equals(preference.getKey())) {
|
||||||
|
final Intent intent = new Intent(mContext, DSULoader.class);
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
preference.setSummary(mContext.getResources().getString(R.string.dsu_loader_description));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.SystemProperties;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class SelectDSUPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SwitchPreference mPreference;
|
||||||
|
@Mock
|
||||||
|
private PreferenceScreen mPreferenceScreen;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private SelectDSUPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mController = new SelectDSUPreferenceController(mContext);
|
||||||
|
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
|
||||||
|
mPreference);
|
||||||
|
mController.displayPreference(mPreferenceScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPreferenceChanged_settingEnabled_turnOnGpuViewUpdates() {
|
||||||
|
mController.handlePreferenceTreeClick(mPreference);
|
||||||
|
String flag = SystemProperties.get(DSULoader.PROPERTY_KEY_FEATURE_FLAG);
|
||||||
|
assertThat(flag.equals("1")).isTrue();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user