Merge "Adding utility class to load customization resources for easier prototype" into ub-launcher3-master

This commit is contained in:
Sunny Goyal 2019-11-28 00:23:37 +00:00 committed by Android (Google) Code Review
commit ec30c5ed51
6 changed files with 209 additions and 54 deletions

View File

@ -15,9 +15,6 @@
-->
<resources>
<!-- Container -->
<item name="container_margin" format="fraction" type="fraction">12%</item>
<!-- Fast scroll -->
<dimen name="fastscroll_popup_width">58dp</dimen>
<dimen name="fastscroll_popup_height">48dp</dimen>

View File

@ -114,4 +114,7 @@
<!-- Recents -->
<item type="id" name="overview_panel"/>
<!-- Configuration resources -->
<array name="dynamic_resources"> </array>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<DynamicResources>
<entry id="@color/delete_target_hover_tint" />
<entry id="@color/delete_target_hover_tint" />
<entry id="@color/delete_target_hover_tint" />
<entry id="@color/delete_target_hover_tint" />
</DynamicResources>

View File

@ -15,6 +15,8 @@
*/
package com.android.launcher3.settings;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.pluginEnabledKey;
@ -24,28 +26,21 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.FlagTogglerPrefUi;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import java.util.List;
import java.util.Set;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceDataStore;
@ -54,6 +49,16 @@ import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreference;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.FlagTogglerPrefUi;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Dev-build only UI allowing developers to toggle flag settings and plugins.
* See {@link FeatureFlags}.
@ -154,44 +159,53 @@ public class DeveloperOptionsFragment extends PreferenceFragment {
PackageManager pm = getContext().getPackageManager();
Set<String> pluginActions = manager.getPluginActions();
ArrayMap<String, ArraySet<String>> plugins = new ArrayMap<>();
ArrayMap<Pair<String, String>, ArrayList<Pair<String, ServiceInfo>>> plugins =
new ArrayMap<>();
Set<String> pluginPermissionApps = pm.getPackagesHoldingPermissions(
new String[]{PLUGIN_PERMISSION}, MATCH_DISABLED_COMPONENTS)
.stream()
.map(pi -> pi.packageName)
.collect(Collectors.toSet());
for (String action : pluginActions) {
String name = toName(action);
List<ResolveInfo> result = pm.queryIntentServices(
new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
new Intent(action), MATCH_DISABLED_COMPONENTS);
for (ResolveInfo info : result) {
String packageName = info.serviceInfo.packageName;
if (!plugins.containsKey(packageName)) {
plugins.put(packageName, new ArraySet<>());
if (!pluginPermissionApps.contains(packageName)) {
continue;
}
plugins.get(packageName).add(name);
Pair<String, String> key = Pair.create(packageName, info.serviceInfo.processName);
if (!plugins.containsKey(key)) {
plugins.put(key, new ArrayList<>());
}
plugins.get(key).add(Pair.create(name, info.serviceInfo));
}
}
List<PackageInfo> apps = pm.getPackagesHoldingPermissions(new String[]{PLUGIN_PERMISSION},
PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
PreferenceDataStore enabled = manager.getPluginEnabler();
apps.forEach(app -> {
if (!plugins.containsKey(app.packageName)) return;
SwitchPreference pref = new PluginPreference(prefContext, app, enabled);
pref.setSummary("Plugins: " + toString(plugins.get(app.packageName)));
mPluginsCategory.addPreference(pref);
PreferenceDataStore enabler = manager.getPluginEnabler();
plugins.forEach((key, si) -> {
String packageName = key.first;
List<ComponentName> componentNames = si.stream()
.map(p -> new ComponentName(packageName, p.second.name))
.collect(Collectors.toList());
if (!componentNames.isEmpty()) {
SwitchPreference pref = new PluginPreference(
prefContext, si.get(0).second.applicationInfo, enabler, componentNames);
pref.setSummary("Plugins: "
+ si.stream().map(p -> p.first).collect(Collectors.joining(", ")));
mPluginsCategory.addPreference(pref);
}
});
}
private String toString(ArraySet<String> plugins) {
StringBuilder b = new StringBuilder();
for (String string : plugins) {
if (b.length() != 0) {
b.append(", ");
}
b.append(string);
}
return b.toString();
}
private String toName(String action) {
String str = action.replace("com.android.systemui.action.PLUGIN_", "");
String str = action.replace("com.android.systemui.action.PLUGIN_", "")
.replace("com.android.launcher3.action.PLUGIN_", "");
StringBuilder b = new StringBuilder();
for (String s : str.split("_")) {
if (b.length() != 0) {
@ -205,18 +219,20 @@ public class DeveloperOptionsFragment extends PreferenceFragment {
private static class PluginPreference extends SwitchPreference {
private final boolean mHasSettings;
private final PackageInfo mInfo;
private final PreferenceDataStore mPluginEnabler;
private final String mPackageName;
private final List<ComponentName> mComponentNames;
public PluginPreference(Context prefContext, PackageInfo info,
PreferenceDataStore pluginEnabler) {
PluginPreference(Context prefContext, ApplicationInfo info,
PreferenceDataStore pluginEnabler, List<ComponentName> componentNames) {
super(prefContext);
PackageManager pm = prefContext.getPackageManager();
mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
.setPackage(info.packageName), 0) != null;
mInfo = info;
mPackageName = info.packageName;
mComponentNames = componentNames;
mPluginEnabler = pluginEnabler;
setTitle(info.applicationInfo.loadLabel(pm));
setTitle(info.loadLabel(pm));
setChecked(isPluginEnabled());
setWidgetLayoutResource(R.layout.switch_preference_with_settings);
}
@ -227,9 +243,7 @@ public class DeveloperOptionsFragment extends PreferenceFragment {
}
private boolean isPluginEnabled() {
for (int i = 0; i < mInfo.services.length; i++) {
ComponentName componentName = new ComponentName(mInfo.packageName,
mInfo.services[i].name);
for (ComponentName componentName : mComponentNames) {
if (!isEnabled(componentName)) {
return false;
}
@ -240,17 +254,14 @@ public class DeveloperOptionsFragment extends PreferenceFragment {
@Override
protected boolean persistBoolean(boolean isEnabled) {
boolean shouldSendBroadcast = false;
for (int i = 0; i < mInfo.services.length; i++) {
ComponentName componentName = new ComponentName(mInfo.packageName,
mInfo.services[i].name);
for (ComponentName componentName : mComponentNames) {
if (isEnabled(componentName) != isEnabled) {
mPluginEnabler.putBoolean(pluginEnabledKey(componentName), isEnabled);
shouldSendBroadcast = true;
}
}
if (shouldSendBroadcast) {
final String pkg = mInfo.packageName;
final String pkg = mPackageName;
final Intent intent = new Intent(PLUGIN_CHANGED,
pkg != null ? Uri.fromParts("package", pkg, null) : null);
getContext().sendBroadcast(intent);
@ -268,8 +279,7 @@ public class DeveloperOptionsFragment extends PreferenceFragment {
: View.GONE);
holder.findViewById(R.id.settings).setOnClickListener(v -> {
ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
mInfo.packageName), 0);
new Intent(ACTION_PLUGIN_SETTINGS).setPackage(mPackageName), 0);
if (result != null) {
v.getContext().startActivity(new Intent().setComponent(
new ComponentName(result.activityInfo.packageName,
@ -278,7 +288,7 @@ public class DeveloperOptionsFragment extends PreferenceFragment {
});
holder.itemView.setOnLongClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", mInfo.packageName, null));
intent.setData(Uri.fromParts("package", mPackageName, null));
getContext().startActivity(intent);
return true;
});

View File

@ -0,0 +1,89 @@
/*
* 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.launcher3.util;
import android.content.Context;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
import androidx.annotation.FractionRes;
import androidx.annotation.IntegerRes;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.ResourceProvider;
/**
* Utility class to support customizing resource values using plugins
*
* To load resources, call
* DynamicResource.provider(context).getInt(resId) or any other supported methods
*
* To allow customization for a particular resource, add them to dynamic_resources.xml
*/
public class DynamicResource implements ResourceProvider, PluginListener<ResourceProvider> {
private static final MainThreadInitializedObject<DynamicResource> INSTANCE =
new MainThreadInitializedObject<>(DynamicResource::new);
private final Context mContext;
private ResourceProvider mPlugin;
private DynamicResource(Context context) {
mContext = context;
PluginManagerWrapper.INSTANCE.get(context).addPluginListener(this,
ResourceProvider.class, false /* allowedMultiple */);
}
@Override
public int getInt(@IntegerRes int resId) {
return mContext.getResources().getInteger(resId);
}
@Override
public float getFraction(@FractionRes int resId) {
return mContext.getResources().getFraction(resId, 1, 1);
}
@Override
public float getDimension(@DimenRes int resId) {
return mContext.getResources().getDimension(resId);
}
@Override
public int getColor(@ColorRes int resId) {
return mContext.getResources().getColor(resId, null);
}
@Override
public void onPluginConnected(ResourceProvider plugin, Context context) {
mPlugin = plugin;
}
@Override
public void onPluginDisconnected(ResourceProvider plugin) {
mPlugin = null;
}
/**
* Returns the currently active or default provider
*/
public static ResourceProvider provider(Context context) {
DynamicResource dr = DynamicResource.INSTANCE.get(context);
ResourceProvider plugin = dr.mPlugin;
return plugin == null ? dr : plugin;
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.systemui.plugins;
import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
* Plugin to support customizing resource
*/
@ProvidesInterface(action = ResourceProvider.ACTION, version = ResourceProvider.VERSION)
public interface ResourceProvider extends Plugin {
String ACTION = "com.android.launcher3.action.PLUGIN_DYNAMIC_RESOURCE";
int VERSION = 1;
/**
* @see android.content.res.Resources#getInteger(int)
*/
int getInt(int resId);
/**
* @see android.content.res.Resources#getFraction(int, int, int)
*/
float getFraction(int resId);
/**
* @see android.content.res.Resources#getDimension(int)
*/
float getDimension(int resId);
/**
* @see android.content.res.Resources#getColor(int)
*/
int getColor(int resId);
}