blob: 6729f7434fad029b27c3b85d57d6d37e83460194 [file] [log] [blame]
/*
* Copyright (C) 2018 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.config;
import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Process;
import android.text.Html;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
import androidx.preference.SwitchPreference;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags.DebugFlag;
/**
* Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
*/
public final class FlagTogglerPrefUi {
private static final String TAG = "FlagTogglerPrefFrag";
private final PreferenceFragmentCompat mFragment;
private final Context mContext;
private final SharedPreferences mSharedPreferences;
private final PreferenceDataStore mDataStore = new PreferenceDataStore() {
@Override
public void putBoolean(String key, boolean value) {
for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
if (flag.key.equals(key)) {
SharedPreferences.Editor editor = mContext.getSharedPreferences(
FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit();
if (value == flag.defaultValue) {
editor.remove(key).apply();
} else {
editor.putBoolean(key, value).apply();
}
updateMenu();
}
}
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
if (flag.key.equals(key)) {
return mContext.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
.getBoolean(key, flag.defaultValue);
}
}
return defaultValue;
}
};
public FlagTogglerPrefUi(PreferenceFragmentCompat fragment) {
mFragment = fragment;
mContext = fragment.getActivity();
mSharedPreferences = mContext.getSharedPreferences(
FLAGS_PREF_NAME, Context.MODE_PRIVATE);
}
public void applyTo(PreferenceGroup parent) {
// For flag overrides we only want to store when the engineer chose to override the
// flag with a different value than the default. That way, when we flip flags in
// future, engineers will pick up the new value immediately. To accomplish this, we use a
// custom preference data store.
for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
SwitchPreference switchPreference = new SwitchPreference(mContext);
switchPreference.setKey(flag.key);
switchPreference.setDefaultValue(flag.defaultValue);
switchPreference.setChecked(getFlagStateFromSharedPrefs(flag));
switchPreference.setTitle(flag.key);
updateSummary(switchPreference, flag);
switchPreference.setPreferenceDataStore(mDataStore);
parent.addPreference(switchPreference);
}
updateMenu();
}
/**
* Updates the summary to show the description and whether the flag overrides the default value.
*/
private void updateSummary(SwitchPreference switchPreference, DebugFlag flag) {
String onWarning = flag.defaultValue ? "" : "<b>OVERRIDDEN</b><br>";
String offWarning = flag.defaultValue ? "<b>OVERRIDDEN</b><br>" : "";
switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.description));
switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.description));
}
private void updateMenu() {
mFragment.setHasOptionsMenu(anyChanged());
mFragment.getActivity().invalidateOptionsMenu();
}
public void onCreateOptionsMenu(Menu menu) {
if (anyChanged()) {
menu.add(0, R.id.menu_apply_flags, 0, "Apply")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
}
public void onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_apply_flags) {
mSharedPreferences.edit().commit();
Log.e(TAG,
"Killing launcher process " + Process.myPid() + " to apply new flag values");
System.exit(0);
}
}
public void onStop() {
if (anyChanged()) {
Toast.makeText(mContext, "Flag won't be applied until you restart launcher",
Toast.LENGTH_LONG).show();
}
}
private boolean getFlagStateFromSharedPrefs(DebugFlag flag) {
return mDataStore.getBoolean(flag.key, flag.defaultValue);
}
private boolean anyChanged() {
for (DebugFlag flag : FeatureFlags.getDebugFlags()) {
if (getFlagStateFromSharedPrefs(flag) != flag.get()) {
return true;
}
}
return false;
}
}