Commit 4eacfd27 authored by Nate Fischer's avatar Nate Fischer Committed by Commit Bot

AW: switch Dev UI to Fragments

This switches Dev UI from Activities to Fragments. The immediate user
benefit is smoother transitions when switching between tools, but this
opens up for opportunities for other navigation methods (ex. bottom nav
bar or nav drawer).

Bug: 1017532
Test: Tested system_webview_apk on L+, monochrome on N+, Trichrome on Q
Test: Click flag UI notification, verify it opens the flags UI fragment
Change-Id: I32eb7a9b2ada6395bad21488e6bd15c802131b7e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2108919
Commit-Queue: Nate Fischer <ntfschr@chromium.org>
Reviewed-by: default avatarHazem Ashmawy <hazems@chromium.org>
Cr-Commit-Position: refs/heads/master@{#753124}
parent fb94892a
...@@ -34,8 +34,9 @@ android_library("nonembedded_java") { ...@@ -34,8 +34,9 @@ android_library("nonembedded_java") {
android_library("devui_java") { android_library("devui_java") {
sources = [ sources = [
"java/src/org/chromium/android_webview/devui/CrashesListActivity.java", "java/src/org/chromium/android_webview/devui/CrashesListFragment.java",
"java/src/org/chromium/android_webview/devui/FlagsActivity.java", "java/src/org/chromium/android_webview/devui/FlagsFragment.java",
"java/src/org/chromium/android_webview/devui/HomeFragment.java",
"java/src/org/chromium/android_webview/devui/MainActivity.java", "java/src/org/chromium/android_webview/devui/MainActivity.java",
"java/src/org/chromium/android_webview/devui/PersistentErrorView.java", "java/src/org/chromium/android_webview/devui/PersistentErrorView.java",
"java/src/org/chromium/android_webview/devui/WebViewPackageError.java", "java/src/org/chromium/android_webview/devui/WebViewPackageError.java",
...@@ -57,6 +58,7 @@ android_library("devui_java") { ...@@ -57,6 +58,7 @@ android_library("devui_java") {
"//base:base_java", "//base:base_java",
"//components/minidump_uploader:minidump_uploader_java", "//components/minidump_uploader:minidump_uploader_java",
"//third_party/android_deps:androidx_annotation_annotation_java", "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:com_android_support_support_fragment_java",
"//ui/android:ui_java", "//ui/android:ui_java",
] ]
android_manifest_for_lint = system_webview_android_manifest android_manifest_for_lint = system_webview_android_manifest
...@@ -117,12 +119,13 @@ android_resources("icon_resources") { ...@@ -117,12 +119,13 @@ android_resources("icon_resources") {
android_resources("devui_resources") { android_resources("devui_resources") {
sources = [ sources = [
"java/res_devui/drawable/blue_circle.xml", "java/res_devui/drawable/blue_circle.xml",
"java/res_devui/layout/activity_crashes_list.xml",
"java/res_devui/layout/activity_flags.xml",
"java/res_devui/layout/activity_main.xml", "java/res_devui/layout/activity_main.xml",
"java/res_devui/layout/crashes_list_item_body.xml", "java/res_devui/layout/crashes_list_item_body.xml",
"java/res_devui/layout/crashes_list_item_header.xml", "java/res_devui/layout/crashes_list_item_header.xml",
"java/res_devui/layout/flag_states.xml", "java/res_devui/layout/flag_states.xml",
"java/res_devui/layout/fragment_crashes_list.xml",
"java/res_devui/layout/fragment_flags.xml",
"java/res_devui/layout/fragment_home.xml",
"java/res_devui/layout/persistent_error_message.xml", "java/res_devui/layout/persistent_error_message.xml",
"java/res_devui/layout/toggleable_flag.xml", "java/res_devui/layout/toggleable_flag.xml",
"java/res_devui/layout/two_line_list_item.xml", "java/res_devui/layout/two_line_list_item.xml",
......
...@@ -51,20 +51,6 @@ ...@@ -51,20 +51,6 @@
android:targetActivity="org.chromium.android_webview.devui.MainActivity" android:targetActivity="org.chromium.android_webview.devui.MainActivity"
android:enabled="false" android:enabled="false"
android:process=":webview_apk" /> {# Explicit process required for monochrome compatibility. #} android:process=":webview_apk" /> {# Explicit process required for monochrome compatibility. #}
<activity android:name="org.chromium.android_webview.devui.CrashesListActivity"
android:label="WebView Crashes"
android:theme="@style/Theme.DevUi.DayNight"
android:launchMode="singleTop"
android:taskAffinity="{{ manifest_package }}.org.chromium.android_webview.devui" {# Explicit taskAffinity to distinguish from monochrome browser task. #}
android:process=":webview_apk"> {# Explicit process required for monochrome compatibility. #}
</activity>
<activity android:name="org.chromium.android_webview.devui.FlagsActivity"
android:label="WebView Flags"
android:theme="@style/Theme.DevUi.DayNight"
android:launchMode="singleTop"
android:taskAffinity="{{ manifest_package }}.org.chromium.android_webview.devui" {# Explicit taskAffinity to distinguish from monochrome browser task. #}
android:process=":webview_apk"> {# Explicit process required for monochrome compatibility. #}
</activity>
<!-- End of WebView Developer UI Activities --> <!-- End of WebView Developer UI Activities -->
<activity android:name="org.chromium.android_webview.nonembedded.LicenseActivity" <activity android:name="org.chromium.android_webview.nonembedded.LicenseActivity"
......
...@@ -15,8 +15,12 @@ ...@@ -15,8 +15,12 @@
layout="@layout/persistent_error_message" layout="@layout/persistent_error_message"
android:id="@+id/webview_package_error"/> android:id="@+id/webview_package_error"/>
<ListView <include
android:id="@+id/main_info_list" layout="@layout/persistent_error_message"
android:id="@+id/crash_consent_error"/>
<FrameLayout
android:id="@+id/content_fragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
......
...@@ -11,14 +11,6 @@ ...@@ -11,14 +11,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<include
layout="@layout/persistent_error_message"
android:id="@+id/webview_package_error"/>
<include
layout="@layout/persistent_error_message"
android:id="@+id/crash_consent_error"/>
<TextView <TextView
android:id="@+id/crashes_summary_textview" android:id="@+id/crashes_summary_textview"
android:layout_width="match_parent" android:layout_width="match_parent"
......
...@@ -12,10 +12,6 @@ ...@@ -12,10 +12,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="10dp"> android:padding="10dp">
<include
layout="@layout/persistent_error_message"
android:id="@+id/webview_package_error"/>
<!--suppress HardcodedText --> <!--suppress HardcodedText -->
<TextView <TextView
android:id="@+id/flags_warning" android:id="@+id/flags_warning"
......
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 The Chromium Authors. All rights reserved. Use of this
source code is governed by a BSD-style license that can be found in the
LICENSE file.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_home"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/main_info_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<TextView <TextView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:visibility="gone"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
......
...@@ -13,8 +13,7 @@ import android.content.ServiceConnection; ...@@ -13,8 +13,7 @@ import android.content.ServiceConnection;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.view.Menu; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewParent; import android.view.ViewParent;
...@@ -25,22 +24,23 @@ import android.widget.ListView; ...@@ -25,22 +24,23 @@ import android.widget.ListView;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.chromium.android_webview.common.DeveloperModeUtils; import org.chromium.android_webview.common.DeveloperModeUtils;
import org.chromium.android_webview.common.Flag; import org.chromium.android_webview.common.Flag;
import org.chromium.android_webview.common.ProductionSupportedFlagList; import org.chromium.android_webview.common.ProductionSupportedFlagList;
import org.chromium.android_webview.common.services.IDeveloperUiService; import org.chromium.android_webview.common.services.IDeveloperUiService;
import org.chromium.android_webview.common.services.ServiceNames; import org.chromium.android_webview.common.services.ServiceNames;
import org.chromium.android_webview.devui.util.NavigationMenuHelper;
import org.chromium.base.Log; import org.chromium.base.Log;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* An activity to toggle experimental WebView flags/features. * A fragment to toggle experimental WebView flags/features.
*/ */
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
public class FlagsActivity extends Activity { public class FlagsFragment extends Fragment {
private static final String TAG = "WebViewDevTools"; private static final String TAG = "WebViewDevTools";
private static final String STATE_DEFAULT = "Default"; private static final String STATE_DEFAULT = "Default";
...@@ -52,46 +52,45 @@ public class FlagsActivity extends Activity { ...@@ -52,46 +52,45 @@ public class FlagsActivity extends Activity {
STATE_DISABLED, STATE_DISABLED,
}; };
private WebViewPackageError mDifferentPackageError;
private Map<String, Boolean> mOverriddenFlags = new HashMap<>(); private Map<String, Boolean> mOverriddenFlags = new HashMap<>();
private FlagsListAdapter mListAdapter; private FlagsListAdapter mListAdapter;
private Context mContext;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { public void onAttach(Context context) {
super.onCreate(savedInstanceState); super.onAttach(context);
mContext = context;
}
setContentView(R.layout.activity_flags); @Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_flags, null);
}
ListView flagsListView = findViewById(R.id.flags_list); @Override
TextView flagsDescriptionView = findViewById(R.id.flags_description); public void onViewCreated(View view, Bundle savedInstanceState) {
Activity activity = (Activity) mContext;
activity.setTitle("WebView Flags");
ListView flagsListView = view.findViewById(R.id.flags_list);
TextView flagsDescriptionView = view.findViewById(R.id.flags_description);
flagsDescriptionView.setText("By enabling these features, you could " flagsDescriptionView.setText("By enabling these features, you could "
+ "lose app data or compromise your security or privacy. Enabled features apply to " + "lose app data or compromise your security or privacy. Enabled features apply to "
+ "WebViews across all apps on the device."); + "WebViews across all apps on the device.");
// Restore flag overrides from the service process to repopulate the UI, if developer mode // Restore flag overrides from the service process to repopulate the UI, if developer mode
// is enabled. // is enabled.
if (DeveloperModeUtils.isDeveloperModeEnabled(getPackageName())) { if (DeveloperModeUtils.isDeveloperModeEnabled(mContext.getPackageName())) {
mOverriddenFlags = DeveloperModeUtils.getFlagOverrides(getPackageName()); mOverriddenFlags = DeveloperModeUtils.getFlagOverrides(mContext.getPackageName());
} }
mListAdapter = new FlagsListAdapter(); mListAdapter = new FlagsListAdapter();
flagsListView.setAdapter(mListAdapter); flagsListView.setAdapter(mListAdapter);
Button resetFlagsButton = findViewById(R.id.reset_flags_button); Button resetFlagsButton = view.findViewById(R.id.reset_flags_button);
resetFlagsButton.setOnClickListener((View view) -> { resetAllFlags(); }); resetFlagsButton.setOnClickListener((View flagButton) -> { resetAllFlags(); });
mDifferentPackageError = new WebViewPackageError(this);
// show the dialog once when the activity is created.
mDifferentPackageError.showDialogIfDifferent();
}
@Override
protected void onResume() {
super.onResume();
// Check package status in onResume() to hide/show the error message if the user
// changes WebView implementation from system settings and then returns back to the
// activity.
mDifferentPackageError.showMessageIfDifferent();
} }
private static int booleanToState(Boolean b) { private static int booleanToState(Boolean b) {
...@@ -150,8 +149,7 @@ public class FlagsActivity extends Activity { ...@@ -150,8 +149,7 @@ public class FlagsActivity extends Activity {
*/ */
private class FlagsListAdapter extends ArrayAdapter<Flag> { private class FlagsListAdapter extends ArrayAdapter<Flag> {
public FlagsListAdapter() { public FlagsListAdapter() {
super(FlagsActivity.this, R.layout.toggleable_flag, super(mContext, R.layout.toggleable_flag, ProductionSupportedFlagList.sFlagList);
ProductionSupportedFlagList.sFlagList);
} }
@Override @Override
...@@ -174,7 +172,7 @@ public class FlagsActivity extends Activity { ...@@ -174,7 +172,7 @@ public class FlagsActivity extends Activity {
flagName.setText(label); flagName.setText(label);
flagDescription.setText(flag.getDescription()); flagDescription.setText(flag.getDescription());
ArrayAdapter<String> adapter = ArrayAdapter<String> adapter =
new ArrayAdapter<>(FlagsActivity.this, R.layout.flag_states, sFlagStates); new ArrayAdapter<>(mContext, R.layout.flag_states, sFlagStates);
adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice); adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
flagToggle.setAdapter(adapter); flagToggle.setAdapter(adapter);
...@@ -207,26 +205,11 @@ public class FlagsActivity extends Activity { ...@@ -207,26 +205,11 @@ public class FlagsActivity extends Activity {
} }
} }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
NavigationMenuHelper.inflate(this, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (NavigationMenuHelper.onOptionsItemSelected(this, item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class FlagsServiceConnection implements ServiceConnection { private class FlagsServiceConnection implements ServiceConnection {
public void start() { public void start() {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClassName( intent.setClassName(mContext.getPackageName(), ServiceNames.DEVELOPER_UI_SERVICE);
FlagsActivity.this.getPackageName(), ServiceNames.DEVELOPER_UI_SERVICE); if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
if (!FlagsActivity.this.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
Log.e(TAG, "Failed to bind to Developer UI service"); Log.e(TAG, "Failed to bind to Developer UI service");
} }
} }
...@@ -234,8 +217,7 @@ public class FlagsActivity extends Activity { ...@@ -234,8 +217,7 @@ public class FlagsActivity extends Activity {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClassName( intent.setClassName(mContext.getPackageName(), ServiceNames.DEVELOPER_UI_SERVICE);
FlagsActivity.this.getPackageName(), ServiceNames.DEVELOPER_UI_SERVICE);
try { try {
IDeveloperUiService.Stub.asInterface(service).setFlagOverrides(mOverriddenFlags); IDeveloperUiService.Stub.asInterface(service).setFlagOverrides(mOverriddenFlags);
} catch (RemoteException e) { } catch (RemoteException e) {
...@@ -243,7 +225,7 @@ public class FlagsActivity extends Activity { ...@@ -243,7 +225,7 @@ public class FlagsActivity extends Activity {
} finally { } finally {
// Unbind when we've sent the flags overrides, since we can always rebind later. The // Unbind when we've sent the flags overrides, since we can always rebind later. The
// service will manage its own lifetime. // service will manage its own lifetime.
FlagsActivity.this.unbindService(this); mContext.unbindService(this);
} }
} }
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview.devui;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.chromium.android_webview.devui.util.WebViewPackageHelper;
import org.chromium.ui.widget.Toast;
import java.util.Locale;
/**
* Dev UI main fragment.
* It shows a summary about WebView package and the device.
*/
public class HomeFragment extends Fragment {
private Context mContext;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, null);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Activity activity = (Activity) mContext;
activity.setTitle("WebView DevTools");
PackageInfo webViewPackage = WebViewPackageHelper.getContextPackageInfo(mContext);
InfoItem[] infoItems = new InfoItem[] {
new InfoItem("WebView package", webViewPackage.packageName),
new InfoItem("WebView version",
String.format(Locale.US, "%s (%s)", webViewPackage.versionName,
webViewPackage.versionCode)),
new InfoItem("Device info",
String.format(Locale.US, "%s - %s", Build.MODEL, Build.FINGERPRINT)),
};
ListView infoListView = view.findViewById(R.id.main_info_list);
ArrayAdapter<InfoItem> itemsArrayAdapter = new InfoListAdapter(infoItems);
infoListView.setAdapter(itemsArrayAdapter);
// Copy item's text to clipboard on long tapping a list item.
infoListView.setOnItemLongClickListener((parent, clickedView, pos, id) -> {
InfoItem item = (InfoItem) parent.getItemAtPosition(pos);
ClipboardManager clipboard =
(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(item.title, item.subtitle);
clipboard.setPrimaryClip(clip);
// Show a toast that the text has been copied.
Toast.makeText(mContext, "Copied " + item.title, Toast.LENGTH_SHORT).show();
return true;
});
}
/**
* A model class for a key-value piece of information to be displayed as a title (key) and
* subtitle (value).
*/
private static class InfoItem {
public static final String UNKNOWN = "Unknown";
public final String title;
public final String subtitle;
public InfoItem(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle == null ? UNKNOWN : subtitle;
}
}
/**
* An ArrayAdapter to show a list of {@code InfoItem} objects.
*
* It uses android stock {@code android.R.layout.simple_list_item_2} which has two {@code
* TextView}; {@code text1} acts as the item title and {@code text2} as the item subtitle.
*/
private class InfoListAdapter extends ArrayAdapter<InfoItem> {
private final InfoItem[] mItems;
public InfoListAdapter(InfoItem[] items) {
super(mContext, R.layout.two_line_list_item, items);
mItems = items;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
// If the the old view is already created then reuse it, else create a new one by layout
// inflation.
if (view == null) {
view = getLayoutInflater().inflate(R.layout.two_line_list_item, null, true);
}
InfoItem item = mItems[position];
TextView title = view.findViewById(android.R.id.text1);
TextView subtitle = view.findViewById(android.R.id.text2);
title.setText(item.title);
subtitle.setText(item.subtitle);
return view;
}
}
}
...@@ -3,34 +3,31 @@ ...@@ -3,34 +3,31 @@
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.android_webview.devui; package org.chromium.android_webview.devui;
import android.app.Activity; import android.content.Intent;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import org.chromium.android_webview.devui.util.NavigationMenuHelper; import androidx.fragment.app.Fragment;
import org.chromium.android_webview.devui.util.WebViewPackageHelper; import androidx.fragment.app.FragmentActivity;
import org.chromium.ui.widget.Toast; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import java.util.Locale; import org.chromium.android_webview.devui.util.NavigationMenuHelper;
/** /**
* Dev UI main activity. * Dev UI main activity.
* It shows a summary about WebView package and the device. * It shows persistent errors and helps to navigate to WebView developer tools.
* It helps to navigate to other WebView developer tools.
*/ */
public class MainActivity extends Activity { public class MainActivity extends FragmentActivity {
private WebViewPackageError mDifferentPackageError; private WebViewPackageError mDifferentPackageError;
private boolean mSwitchFragmentOnResume;
// Keep in sync with DeveloperUiService.java
private static final String FRAGMENT_ID_INTENT_EXTRA = "fragment-id";
private static final int FRAGMENT_ID_HOME = 0;
private static final int FRAGMENT_ID_CRASHES = 1;
private static final int FRAGMENT_ID_FLAGS = 2;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
...@@ -38,38 +35,22 @@ public class MainActivity extends Activity { ...@@ -38,38 +35,22 @@ public class MainActivity extends Activity {
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
PackageInfo webViewPackage = WebViewPackageHelper.getContextPackageInfo(this); // Let onResume handle showing the initial Fragment.
InfoItem[] infoItems = new InfoItem[] { mSwitchFragmentOnResume = true;
new InfoItem("WebView package", webViewPackage.packageName),
new InfoItem("WebView version",
String.format(Locale.US, "%s (%s)", webViewPackage.versionName,
webViewPackage.versionCode)),
new InfoItem("Device info",
String.format(Locale.US, "%s - %s", Build.MODEL, Build.FINGERPRINT)),
};
ListView infoListView = findViewById(R.id.main_info_list);
ArrayAdapter<InfoItem> itemsArrayAdapter = new InfoListAdapter(infoItems);
infoListView.setAdapter(itemsArrayAdapter);
// Copy item's text to clipboard on long tapping a list item.
infoListView.setOnItemLongClickListener((parent, view, pos, id) -> {
InfoItem item = (InfoItem) parent.getItemAtPosition(pos);
ClipboardManager clipboard =
(ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(item.title, item.subtitle);
clipboard.setPrimaryClip(clip);
// Show a toast that the text has been copied.
Toast.makeText(MainActivity.this, "Copied " + item.title, Toast.LENGTH_SHORT).show();
return true;
});
mDifferentPackageError = new WebViewPackageError(this); mDifferentPackageError = new WebViewPackageError(this);
// show the dialog once when the activity is created. // show the dialog once when the activity is created.
mDifferentPackageError.showDialogIfDifferent(); mDifferentPackageError.showDialogIfDifferent();
} }
@Override
protected void onNewIntent(Intent intent) {
// Store the Intent so we can switch Fragments in onResume (which is called next). Only need
// to switch Fragment if the Intent specifies to do so.
setIntent(intent);
mSwitchFragmentOnResume = intent.hasExtra(FRAGMENT_ID_INTENT_EXTRA);
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
...@@ -77,54 +58,44 @@ public class MainActivity extends Activity { ...@@ -77,54 +58,44 @@ public class MainActivity extends Activity {
// changes WebView implementation from system settings and then returns back to the // changes WebView implementation from system settings and then returns back to the
// activity. // activity.
mDifferentPackageError.showMessageIfDifferent(); mDifferentPackageError.showMessageIfDifferent();
}
/** // Don't change Fragment unless we have a new Intent, since the user might just be coming
* A model class for a key-value piece of information to be displayed as a title (key) and // back to this through the task switcher.
* subtitle (value). if (!mSwitchFragmentOnResume) return;
*/
private static class InfoItem { // Ensure we only switch the first time we see a new Intent.
public static final String UNKNOWN = "Unknown"; mSwitchFragmentOnResume = false;
public final String title;
public final String subtitle; // Default to HomeFragment if not specified.
int fragmentId = FRAGMENT_ID_HOME;
public InfoItem(String title, String subtitle) { // FRAGMENT_ID_INTENT_EXTRA is an optional extra to specify which fragment to open. At the
this.title = title; // moment, it's specified only by DeveloperUiService (so make sure these constants stay in
this.subtitle = subtitle == null ? UNKNOWN : subtitle; // sync).
Bundle extras = getIntent().getExtras();
if (extras != null) {
fragmentId = extras.getInt(FRAGMENT_ID_INTENT_EXTRA, fragmentId);
} }
}
/** Fragment fragment = null;
* An ArrayAdapter to show a list of {@code InfoItem} objects. switch (fragmentId) {
* default:
* It uses android stock {@code android.R.layout.simple_list_item_2} which has two {@code // Fall through.
* TextView}; {@code text1} acts as the item title and {@code text2} as the item subtitle. case FRAGMENT_ID_HOME:
*/ fragment = new HomeFragment();
private class InfoListAdapter extends ArrayAdapter<InfoItem> { break;
private final InfoItem[] mItems; case FRAGMENT_ID_CRASHES:
fragment = new CrashesListFragment();
public InfoListAdapter(InfoItem[] items) { break;
super(MainActivity.this, R.layout.two_line_list_item, items); case FRAGMENT_ID_FLAGS:
mItems = items; fragment = new FlagsFragment();
break;
} }
assert fragment != null;
@Override FragmentManager fm = getSupportFragmentManager();
public View getView(int position, View view, ViewGroup parent) { FragmentTransaction transaction = fm.beginTransaction();
// If the the old view is already created then reuse it, else create a new one by layout transaction.replace(R.id.content_fragment, fragment);
// inflation. transaction.commit();
if (view == null) {
view = getLayoutInflater().inflate(R.layout.two_line_list_item, null, true);
}
InfoItem item = mItems[position];
TextView title = view.findViewById(android.R.id.text1);
TextView subtitle = view.findViewById(android.R.id.text2);
title.setText(item.title);
subtitle.setText(item.subtitle);
return view;
}
} }
@Override @Override
......
...@@ -3,16 +3,20 @@ ...@@ -3,16 +3,20 @@
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.android_webview.devui.util; package org.chromium.android_webview.devui.util;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import org.chromium.android_webview.devui.CrashesListActivity; import androidx.fragment.app.Fragment;
import org.chromium.android_webview.devui.FlagsActivity; import androidx.fragment.app.FragmentActivity;
import org.chromium.android_webview.devui.MainActivity; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import org.chromium.android_webview.devui.CrashesListFragment;
import org.chromium.android_webview.devui.FlagsFragment;
import org.chromium.android_webview.devui.HomeFragment;
import org.chromium.android_webview.devui.R; import org.chromium.android_webview.devui.R;
/** /**
...@@ -24,9 +28,10 @@ public final class NavigationMenuHelper { ...@@ -24,9 +28,10 @@ public final class NavigationMenuHelper {
/** /**
* Inflate the navigation menu in the given {@code activity} options menu. * Inflate the navigation menu in the given {@code activity} options menu.
* *
* This should be called inside {@code Activity#onCreateOptionsMenu} method. * This should be called inside {@link android.app.Activity#onCreateOptionsMenu} or
* {@link Fragment#onCreateOptionsMenu}.
*/ */
public static void inflate(Activity activity, Menu menu) { public static void inflate(FragmentActivity activity, Menu menu) {
activity.getMenuInflater().inflate(R.menu.navigation_menu, menu); activity.getMenuInflater().inflate(R.menu.navigation_menu, menu);
// Switching WebView providers is possible only from API >= 24. // Switching WebView providers is possible only from API >= 24.
...@@ -44,19 +49,25 @@ public final class NavigationMenuHelper { ...@@ -44,19 +49,25 @@ public final class NavigationMenuHelper {
* This should be called inside {@code Activity#onOptionsItemSelected} method. * This should be called inside {@code Activity#onOptionsItemSelected} method.
* @return {@code true} if the item selection event is consumed. * @return {@code true} if the item selection event is consumed.
*/ */
public static boolean onOptionsItemSelected(Activity activity, MenuItem item) { public static boolean onOptionsItemSelected(FragmentActivity activity, MenuItem item) {
Fragment fragment = null;
if (item.getItemId() == R.id.nav_menu_crash_ui) { if (item.getItemId() == R.id.nav_menu_crash_ui) {
activity.startActivity(new Intent(activity, CrashesListActivity.class)); fragment = new CrashesListFragment();
} else if (item.getItemId() == R.id.nav_menu_flags_ui) { } else if (item.getItemId() == R.id.nav_menu_flags_ui) {
activity.startActivity(new Intent(activity, FlagsActivity.class)); fragment = new FlagsFragment();
} else if (item.getItemId() == R.id.nav_menu_main_ui) { } else if (item.getItemId() == R.id.nav_menu_main_ui) {
activity.startActivity(new Intent(activity, MainActivity.class)); fragment = new HomeFragment();
} else if (item.getItemId() == R.id.nav_menu_switch_provider } else if (item.getItemId() == R.id.nav_menu_switch_provider
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
activity.startActivity(new Intent(Settings.ACTION_WEBVIEW_SETTINGS)); activity.startActivity(new Intent(Settings.ACTION_WEBVIEW_SETTINGS));
} else { return true;
return false;
} }
if (fragment == null) return false;
FragmentManager fm = activity.getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.content_fragment, fragment);
transaction.commit();
return true; return true;
} }
......
...@@ -36,6 +36,12 @@ public final class DeveloperUiService extends Service { ...@@ -36,6 +36,12 @@ public final class DeveloperUiService extends Service {
private static final String CHANNEL_ID = "DevUiChannel"; private static final String CHANNEL_ID = "DevUiChannel";
private static final int FLAG_OVERRIDE_NOTIFICATION_ID = 1; private static final int FLAG_OVERRIDE_NOTIFICATION_ID = 1;
// Keep in sync with MainActivity.java
private static final String FRAGMENT_ID_INTENT_EXTRA = "fragment-id";
private static final int FRAGMENT_ID_HOME = 0;
private static final int FRAGMENT_ID_CRASHES = 1;
private static final int FRAGMENT_ID_FLAGS = 2;
private static final Object sLock = new Object(); private static final Object sLock = new Object();
@GuardedBy("sLock") @GuardedBy("sLock")
private static Map<String, Boolean> sOverriddenFlags = new HashMap<>(); private static Map<String, Boolean> sOverriddenFlags = new HashMap<>();
...@@ -106,7 +112,8 @@ public final class DeveloperUiService extends Service { ...@@ -106,7 +112,8 @@ public final class DeveloperUiService extends Service {
Intent notificationIntent = new Intent(); Intent notificationIntent = new Intent();
notificationIntent.setClassName( notificationIntent.setClassName(
getPackageName(), "org.chromium.android_webview.devui.FlagsActivity"); getPackageName(), "org.chromium.android_webview.devui.MainActivity");
notificationIntent.putExtra(FRAGMENT_ID_INTENT_EXTRA, FRAGMENT_ID_FLAGS);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification.Builder builder = Notification.Builder builder =
......
...@@ -1022,22 +1022,6 @@ ...@@ -1022,22 +1022,6 @@
android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true"/> android:value="true"/>
</activity> </activity>
<activity
android:label="WebView
Crashes"
android:launchMode="singleTop"
android:name="org.chromium.android_webview.devui.CrashesListActivity"
android:process=":webview_apk"
android:taskAffinity="org.chromium.chrome.org.chromium.android_webview.devui"
android:theme="@style/Theme.DevUi.DayNight"/>
<activity
android:label="WebView
Flags"
android:launchMode="singleTop"
android:name="org.chromium.android_webview.devui.FlagsActivity"
android:process=":webview_apk"
android:taskAffinity="org.chromium.chrome.org.chromium.android_webview.devui"
android:theme="@style/Theme.DevUi.DayNight"/>
<activity <activity
android:enabled="false" android:enabled="false"
android:excludeFromRecents="true" android:excludeFromRecents="true"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment