Removing custom androidx pref + start of vector icons

This commit is contained in:
Jay 2020-01-05 16:06:09 -08:00
parent c516078531
commit e342d4960c
32 changed files with 8 additions and 1609 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M18,4l-4,4h3v7c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2V8c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8v7H2l4,4 4,-4H7V8c0,-1.1 0.9,-2 2,-2s2,0.9 2,2v7c0,2.21 1.79,4 4,4s4,-1.79 4,-4V8h3l-4,-4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M18,4l-4,4h3v7c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2V8c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8v7H2l4,4 4,-4H7V8c0,-1.1 0.9,-2 2,-2s2,0.9 2,2v7c0,2.21 1.79,4 4,4s4,-1.79 4,-4V8h3l-4,-4z"/>
</vector>

View File

@ -25,13 +25,13 @@
<item
android:id="@+id/action_migrate"
android:icon="@drawable/baseline_swap_calls_white_24"
android:icon="@drawable/ic_swap_calls_white_24dp"
android:title="@string/label_migration"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_hide_title"
android:icon="@drawable/baseline_swap_calls_white_24"
android:icon="@drawable/ic_swap_calls_white_24dp"
android:title="@string/label_hide_title"
app:showAsAction="never" />

View File

@ -1,29 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
buildToolsVersion '29.0.2'
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
encoding = 'UTF-8'
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.preference:preference:1.1.0'
compileOnly 'com.bluelinelabs:conductor:2.1.5'
}

View File

@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\len\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,3 +0,0 @@
<manifest package="androidx.preference.conductor">
</manifest>

View File

@ -1,107 +0,0 @@
/*
* Copyright (C) 2015 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 androidx.preference;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
public class EditTextPreferenceDialogController extends PreferenceDialogController {
private static final String SAVE_STATE_TEXT = "EditTextPreferenceDialogController.text";
private EditText mEditText;
private CharSequence mText;
public static EditTextPreferenceDialogController newInstance(String key) {
EditTextPreferenceDialogController
controller = new EditTextPreferenceDialogController();
controller.getArgs().putString(ARG_KEY, key);
return controller;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
mText = getEditTextPreference().getText();
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putCharSequence(SAVE_STATE_TEXT, mText);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mText = savedInstanceState.getCharSequence(SAVE_STATE_TEXT);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
mEditText = view.findViewById(android.R.id.edit);
mEditText.requestFocus();
if (mEditText == null) {
throw new IllegalStateException("Dialog view must contain an EditText with id" +
" @android:id/edit");
}
mEditText.setText(mText);
// Place cursor at the end
mEditText.setSelection(mEditText.getText().length());
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
mEditText = null;
}
private EditTextPreference getEditTextPreference() {
return (EditTextPreference) getPreference();
}
/** @hide */
@RestrictTo(LIBRARY_GROUP)
@Override
protected boolean needInputMethod() {
// We want the input method to show, if possible, when dialog is displayed
return true;
}
@Override
public void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
String value = mEditText.getText().toString();
if (getEditTextPreference().callChangeListener(value)) {
getEditTextPreference().setText(value);
}
}
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright (C) 2015 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 androidx.preference;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
public class ListPreferenceDialogController extends PreferenceDialogController {
private static final String SAVE_STATE_INDEX = "ListPreferenceDialogController.index";
private static final String SAVE_STATE_ENTRIES = "ListPreferenceDialogController.entries";
private static final String SAVE_STATE_ENTRY_VALUES =
"ListPreferenceDialogController.entryValues";
@SuppressWarnings("WeakerAccess") /* synthetic access */
private int mClickedDialogEntryIndex;
private CharSequence[] mEntries;
private CharSequence[] mEntryValues;
public static ListPreferenceDialogController newInstance(String key) {
ListPreferenceDialogController controller =
new ListPreferenceDialogController();
controller.getArgs().putString(ARG_KEY, key);
return controller;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final ListPreference preference = getListPreference();
if (preference.getEntries() == null || preference.getEntryValues() == null) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array.");
}
mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
mEntries = preference.getEntries();
mEntryValues = preference.getEntryValues();
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex);
outState.putCharSequenceArray(SAVE_STATE_ENTRIES, mEntries);
outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0);
mEntries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES);
mEntryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
}
private ListPreference getListPreference() {
return (ListPreference) getPreference();
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which;
/*
* Clicking on an item simulates the positive button
* click, and dismisses the dialog.
*/
ListPreferenceDialogController.this.onClick(dialog,
DialogInterface.BUTTON_POSITIVE);
dialog.dismiss();
}
});
/*
* The typical interaction for list-based dialogs is to have
* click-on-an-item dismiss the dialog instead of the user having to
* press 'Ok'.
*/
builder.setPositiveButton(null, null);
}
@Override
public void onDialogClosed(boolean positiveResult) {
final ListPreference preference = getListPreference();
if (positiveResult && mClickedDialogEntryIndex >= 0) {
String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (preference.callChangeListener(value)) {
preference.setValue(value);
}
}
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright (C) 2016 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 androidx.preference;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.MultiSelectListPreference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@SuppressWarnings("RestrictedApi")
public class MultiSelectListPreferenceDialogController extends PreferenceDialogController {
private static final String SAVE_STATE_VALUES =
"MultiSelectListPreferenceDialogController.values";
private static final String SAVE_STATE_CHANGED =
"MultiSelectListPreferenceDialogController.changed";
private static final String SAVE_STATE_ENTRIES =
"MultiSelectListPreferenceDialogController.entries";
private static final String SAVE_STATE_ENTRY_VALUES =
"MultiSelectListPreferenceDialogController.entryValues";
@SuppressWarnings("WeakerAccess") /* synthetic access */
Set<String> mNewValues = new HashSet<>();
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean mPreferenceChanged;
@SuppressWarnings("WeakerAccess") /* synthetic access */
CharSequence[] mEntries;
@SuppressWarnings("WeakerAccess") /* synthetic access */
CharSequence[] mEntryValues;
public static MultiSelectListPreferenceDialogController newInstance(String key) {
MultiSelectListPreferenceDialogController controller =
new MultiSelectListPreferenceDialogController();
controller.getArgs().putString(ARG_KEY, key);
return controller;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final MultiSelectListPreference preference = getListPreference();
if (preference.getEntries() == null || preference.getEntryValues() == null) {
throw new IllegalStateException(
"MultiSelectListPreference requires an entries array and " +
"an entryValues array.");
}
mNewValues.clear();
mNewValues.addAll(preference.getValues());
mPreferenceChanged = false;
mEntries = preference.getEntries();
mEntryValues = preference.getEntryValues();
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList(SAVE_STATE_VALUES, new ArrayList<>(mNewValues));
outState.putBoolean(SAVE_STATE_CHANGED, mPreferenceChanged);
outState.putCharSequenceArray(SAVE_STATE_ENTRIES, mEntries);
outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mNewValues.clear();
mNewValues.addAll(savedInstanceState.getStringArrayList(SAVE_STATE_VALUES));
mPreferenceChanged = savedInstanceState.getBoolean(SAVE_STATE_CHANGED, false);
mEntries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES);
mEntryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
}
private MultiSelectListPreference getListPreference() {
return (MultiSelectListPreference) getPreference();
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
final int entryCount = mEntryValues.length;
final boolean[] checkedItems = new boolean[entryCount];
for (int i = 0; i < entryCount; i++) {
checkedItems[i] = mNewValues.contains(mEntryValues[i].toString());
}
builder.setMultiChoiceItems(mEntries, checkedItems,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if (isChecked) {
mPreferenceChanged |= mNewValues.add(
mEntryValues[which].toString());
} else {
mPreferenceChanged |= mNewValues.remove(
mEntryValues[which].toString());
}
}
});
}
@Override
public void onDialogClosed(boolean positiveResult) {
final MultiSelectListPreference preference = getListPreference();
if (positiveResult && mPreferenceChanged) {
final Set<String> values = mNewValues;
if (preference.callChangeListener(values)) {
preference.setValues(values);
}
}
mPreferenceChanged = false;
}
}

View File

@ -1,813 +0,0 @@
/*
* Copyright (C) 2015 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 androidx.preference;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.XmlRes;
import androidx.fragment.app.Fragment;
import androidx.preference.MultiSelectListPreference;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bluelinelabs.conductor.RestoreViewOnCreateController;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
/**
* Shows a hierarchy of {@link Preference} objects as
* lists. These preferences will
* automatically save to {@link android.content.SharedPreferences} as the user interacts with
* them. To retrieve an instance of {@link android.content.SharedPreferences} that the
* preference hierarchy in this fragment will use, call
* {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)}
* with a context in the same package as this fragment.
* <p>
* Furthermore, the preferences shown will follow the visual style of system
* preferences. It is easy to create a hierarchy of preferences (that can be
* shown on multiple screens) via XML. For these reasons, it is recommended to
* use this fragment (as a superclass) to deal with preferences in applications.
* <p>
* A {@link PreferenceScreen} object should be at the top of the preference
* hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
* denote a screen break--that is the preferences contained within subsequent
* {@link PreferenceScreen} should be shown on another screen. The preference
* framework handles this by calling {@link #onNavigateToScreen(PreferenceScreen)}.
* <p>
* The preference hierarchy can be formed in multiple ways:
* <li> From an XML file specifying the hierarchy
* <li> From different {@link android.app.Activity Activities} that each specify its own
* preferences in an XML file via {@link android.app.Activity} meta-data
* <li> From an object hierarchy rooted with {@link PreferenceScreen}
* <p>
* To inflate from XML, use the {@link #addPreferencesFromResource(int)}. The
* root element should be a {@link PreferenceScreen}. Subsequent elements can point
* to actual {@link Preference} subclasses. As mentioned above, subsequent
* {@link PreferenceScreen} in the hierarchy will result in the screen break.
* <p>
* To specify an object hierarchy rooted with {@link PreferenceScreen}, use
* {@link #setPreferenceScreen(PreferenceScreen)}.
* <p>
* As a convenience, this fragment implements a click listener for any
* preference in the current hierarchy, see
* {@link #onPreferenceTreeClick(Preference)}.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For information about using {@code PreferenceFragment},
* read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
* guide.</p>
* </div>
*
* <a name="SampleCode"></a>
* <h3>Sample Code</h3>
*
* <p>The following sample code shows a simple preference fragment that is
* populated from a resource. The resource it loads is:</p>
*
* {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml preferences}
*
* <p>The fragment implementation itself simply populates the preferences
* when created. Note that the preferences framework takes care of loading
* the current values out of the app preferences and writing them when changed:</p>
*
* {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/java/com/example/android/supportpreference/FragmentSupportPreferencesCompat.java
* support_fragment_compat}
*
* @see Preference
* @see PreferenceScreen
*/
@SuppressWarnings({"WeakerAccess", "unused", "HandlerLeak", "JavaDoc", "RestrictedApi"})
public abstract class PreferenceController extends RestoreViewOnCreateController implements
PreferenceManager.OnDisplayPreferenceDialogListener,
DialogPreference.TargetFragment {
/**
* Fragment argument used to specify the tag of the desired root
* {@link androidx.preference.PreferenceScreen} object.
*/
public static final String ARG_PREFERENCE_ROOT =
"androidx.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
private static final String PREFERENCES_TAG = "android:preferences";
private static final String DIALOG_FRAGMENT_TAG =
"androidx.preference.PreferenceFragment.DIALOG";
private PreferenceManager mPreferenceManager;
RecyclerView mList;
private boolean mHavePrefs;
private boolean mInitDone;
private Context mStyledContext;
private int mLayoutResId = R.layout.preference_list_fragment;
private DividerDecoration mDividerDecoration = null;
private static final int MSG_BIND_PREFERENCES = 1;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BIND_PREFERENCES:
bindPreferences();
break;
}
}
};
final private Runnable mRequestFocus = new Runnable() {
@Override
public void run() {
mList.focusableViewAvailable(mList);
}
};
private Runnable mSelectPreferenceRunnable;
/**
* Interface that PreferenceFragment's containing activity should
* implement to be able to process preference items that wish to
* switch to a specified fragment.
*/
public interface OnPreferenceStartFragmentCallback {
/**
* Called when the user has clicked on a Preference that has
* a fragment class name associated with it. The implementation
* should instantiate and switch to an instance of the given
* fragment.
* @param caller The fragment requesting navigation.
* @param pref The preference requesting the fragment.
* @return true if the fragment creation has been handled
*/
boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref);
}
/**
* Interface that PreferenceFragment's containing activity should
* implement to be able to process preference items that wish to
* switch to a new screen of preferences.
*/
public interface OnPreferenceStartScreenCallback {
/**
* Called when the user has clicked on a PreferenceScreen item in order to navigate to a new
* screen of preferences.
* @param caller The fragment requesting navigation.
* @param pref The preference screen to navigate to.
* @return true if the screen navigation has been handled
*/
boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref);
}
public interface OnPreferenceDisplayDialogCallback {
/**
* @param caller The fragment containing the preference requesting the dialog.
* @param pref The preference requesting the dialog.
* @return true if the dialog creation has been handled.
*/
boolean onPreferenceDisplayDialog(PreferenceController caller, Preference pref);
}
/**
* Convenience constructor for use when no arguments are needed.
*/
public PreferenceController() {
super(null);
}
/**
* Constructor that takes arguments that need to be retained across restarts.
*
* @param args Any arguments that need to be retained.
*/
public PreferenceController(@Nullable Bundle args) {
super(args);
}
/**
* Called during {@link #onCreate(Bundle)} to supply the preferences for this fragment.
* Subclasses are expected to call {@link #setPreferenceScreen(PreferenceScreen)} either
* directly or via helper methods such as {@link #addPreferencesFromResource(int)}.
*
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
* @param rootKey If non-null, this preference fragment should be rooted at the
* {@link androidx.preference.PreferenceScreen} with this key.
*/
public abstract void onCreatePreferences(Bundle savedInstanceState, String rootKey);
@Override
@NonNull
public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container,
@Nullable Bundle savedInstanceState) {
mInitDone = false;
mHavePrefs = false;
final TypedValue tv = new TypedValue();
getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
int theme = tv.resourceId;
if (theme == 0) {
// Fallback to default theme.
theme = R.style.PreferenceThemeOverlay;
}
mStyledContext = new ContextThemeWrapper(getActivity(), theme);
mPreferenceManager = new PreferenceManager(mStyledContext);
final String rootKey = getArgs().getString(ARG_PREFERENCE_ROOT);
onCreatePreferences(savedInstanceState, rootKey);
TypedArray a = mStyledContext.obtainStyledAttributes(null,
R.styleable.PreferenceFragmentCompat,
R.attr.preferenceFragmentCompatStyle,
0);
mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
mLayoutResId);
mDividerDecoration = new DividerDecoration();
final Drawable divider = a.getDrawable(
R.styleable.PreferenceFragmentCompat_android_divider);
final int dividerHeight = a.getDimensionPixelSize(
R.styleable.PreferenceFragmentCompat_android_dividerHeight, -1);
final boolean allowDividerAfterLastItem = a.getBoolean(
R.styleable.PreferenceFragmentCompat_allowDividerAfterLastItem, true);
a.recycle();
final LayoutInflater themedInflater = inflater.cloneInContext(mStyledContext);
final View view = themedInflater.inflate(mLayoutResId, container, false);
final View rawListContainer = view.findViewById(AndroidResources.ANDROID_R_LIST_CONTAINER);
if (!(rawListContainer instanceof ViewGroup)) {
throw new RuntimeException("Content has view with id attribute "
+ "'android.R.id.list_container' that is not a ViewGroup class");
}
final ViewGroup listContainer = (ViewGroup) rawListContainer;
final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer,
savedInstanceState);
if (listView == null) {
throw new RuntimeException("Could not create RecyclerView");
}
mList = listView;
listView.addItemDecoration(mDividerDecoration);
setDivider(divider);
if (dividerHeight != -1) {
setDividerHeight(dividerHeight);
}
mDividerDecoration.setAllowDividerAfterLastItem(allowDividerAfterLastItem);
// If mList isn't present in the view hierarchy, add it. mList is automatically inflated
// on an Auto device so don't need to add it.
if (mList.getParent() == null) {
listContainer.addView(mList);
}
mHandler.post(mRequestFocus);
onViewCreated(view, savedInstanceState);
return view;
}
/**
* Sets the drawable that will be drawn between each item in the list.
* <p>
* <strong>Note:</strong> If the drawable does not have an intrinsic
* height, you should also call {@link #setDividerHeight(int)}.
*
* @param divider the drawable to use
* @attr ref R.styleable#PreferenceFragmentCompat_android_divider
*/
public void setDivider(Drawable divider) {
if (mDividerDecoration != null) {
mDividerDecoration.setDivider(divider);
}
}
/**
* Sets the height of the divider that will be drawn between each item in the list. Calling
* this will override the intrinsic height as set by {@link #setDivider(Drawable)}
*
* @param height The new height of the divider in pixels.
* @attr ref R.styleable#PreferenceFragmentCompat_android_dividerHeight
*/
public void setDividerHeight(int height) {
if (mDividerDecoration != null) {
mDividerDecoration.setDividerHeight(height);
}
}
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
if (container != null) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.restoreHierarchyState(container);
}
}
}
if (mHavePrefs) {
bindPreferences();
if (mSelectPreferenceRunnable != null) {
mSelectPreferenceRunnable.run();
mSelectPreferenceRunnable = null;
}
}
mInitDone = true;
}
@Override
public void onAttach(@NonNull View view) {
super.onAttach(view);
mPreferenceManager.setOnDisplayPreferenceDialogListener(this);
}
@Override
public void onDetach(@NonNull View view) {
super.onDetach(view);
mPreferenceManager.setOnDisplayPreferenceDialogListener(null);
}
@Override
public void onDestroyView(@NonNull View view) {
mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES);
if (mHavePrefs) {
unbindPreferences();
}
mList = null;
mPreferenceManager = null;
mStyledContext = null;
mDividerDecoration = null;
super.onDestroyView(view);
}
@Override
protected void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
super.onSaveViewState(view, outState);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
Bundle container = new Bundle();
preferenceScreen.saveHierarchyState(container);
outState.putBundle(PREFERENCES_TAG, container);
}
}
/**
* Returns the {@link PreferenceManager} used by this fragment.
* @return The {@link PreferenceManager}.
*/
public PreferenceManager getPreferenceManager() {
return mPreferenceManager;
}
/**
* Sets the root of the preference hierarchy that this fragment is showing.
*
* @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
*/
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
onUnbindPreferences();
mHavePrefs = true;
if (mInitDone) {
postBindPreferences();
}
}
}
/**
* Gets the root of the preference hierarchy that this fragment is showing.
*
* @return The {@link PreferenceScreen} that is the root of the preference
* hierarchy.
*/
public PreferenceScreen getPreferenceScreen() {
return mPreferenceManager.getPreferenceScreen();
}
/**
* Inflates the given XML resource and adds the preference hierarchy to the current
* preference hierarchy.
*
* @param preferencesResId The XML resource ID to inflate.
*/
public void addPreferencesFromResource(@XmlRes int preferencesResId) {
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromResource(mStyledContext,
preferencesResId, getPreferenceScreen()));
}
/**
* Inflates the given XML resource and replaces the current preference hierarchy (if any) with
* the preference hierarchy rooted at {@code key}.
*
* @param preferencesResId The XML resource ID to inflate.
* @param key The preference key of the {@link androidx.preference.PreferenceScreen}
* to use as the root of the preference hierarchy, or null to use the root
* {@link androidx.preference.PreferenceScreen}.
*/
public void setPreferencesFromResource(@XmlRes int preferencesResId, @Nullable String key) {
requirePreferenceManager();
final PreferenceScreen xmlRoot = mPreferenceManager.inflateFromResource(mStyledContext,
preferencesResId, null);
final Preference root;
if (key != null) {
root = xmlRoot.findPreference(key);
if (!(root instanceof PreferenceScreen)) {
throw new IllegalArgumentException("Preference object with key " + key
+ " is not a PreferenceScreen");
}
} else {
root = xmlRoot;
}
setPreferenceScreen((PreferenceScreen) root);
}
/**
* Finds a {@link Preference} based on its key.
*
* @param key The key of the preference to retrieve.
* @return The {@link Preference} with the key, or null.
* @see androidx.preference.PreferenceGroup#findPreference(CharSequence)
*/
@Override
public Preference findPreference(CharSequence key) {
if (mPreferenceManager == null) {
return null;
}
return mPreferenceManager.findPreference(key);
}
private void requirePreferenceManager() {
if (mPreferenceManager == null) {
throw new RuntimeException("This should be called after super.onCreate.");
}
}
private void postBindPreferences() {
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
getListView().setAdapter(onCreateAdapter(preferenceScreen));
preferenceScreen.onAttached();
}
onBindPreferences();
}
private void unbindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.onDetached();
}
onUnbindPreferences();
}
/** @hide */
@RestrictTo(LIBRARY_GROUP)
protected void onBindPreferences() {
}
/** @hide */
@RestrictTo(LIBRARY_GROUP)
protected void onUnbindPreferences() {
}
public final RecyclerView getListView() {
return mList;
}
/**
* Creates the {@link RecyclerView} used to display the preferences.
* Subclasses may override this to return a customized
* {@link RecyclerView}.
* @param inflater The LayoutInflater object that can be used to inflate the
* {@link RecyclerView}.
* @param parent The parent {@link android.view.View} that the RecyclerView will be attached to.
* This method should not add the view itself, but this can be used to generate
* the LayoutParams of the view.
* @param savedInstanceState If non-null, this view is being re-constructed from a previous
* saved state as given here
* @return A new RecyclerView object to be placed into the view hierarchy
*/
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
// If device detected is Auto, use Auto's custom layout that contains a custom ViewGroup
// wrapping a RecyclerView
if (mStyledContext.getPackageManager().hasSystemFeature(PackageManager
.FEATURE_AUTOMOTIVE)) {
RecyclerView recyclerView = parent.findViewById(R.id.recycler_view);
if (recyclerView != null) {
return recyclerView;
}
}
RecyclerView recyclerView = (RecyclerView) inflater
.inflate(R.layout.preference_recyclerview, parent, false);
recyclerView.setLayoutManager(onCreateLayoutManager());
recyclerView.setAccessibilityDelegateCompat(
new PreferenceRecyclerViewAccessibilityDelegate(recyclerView));
return recyclerView;
}
/**
* Called from {@link #onCreateRecyclerView} to create the
* {@link RecyclerView.LayoutManager} for the created
* {@link RecyclerView}.
* @return A new {@link RecyclerView.LayoutManager} instance.
*/
public RecyclerView.LayoutManager onCreateLayoutManager() {
return new LinearLayoutManager(getActivity());
}
/**
* Creates the root adapter.
*
* @param preferenceScreen Preference screen object to create the adapter for.
* @return An adapter that contains the preferences contained in this {@link PreferenceScreen}.
*/
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen);
}
/**
* Called when a preference in the tree requests to display a dialog. Subclasses should
* override this method to display custom dialogs or to handle dialogs for custom preference
* classes.
*
* @param preference The Preference object requesting the dialog.
*/
@Override
public void onDisplayPreferenceDialog(Preference preference) {
boolean handled = false;
if (getCallbackFragment() instanceof OnPreferenceDisplayDialogCallback) {
handled = ((OnPreferenceDisplayDialogCallback) getCallbackFragment())
.onPreferenceDisplayDialog(this, preference);
}
if (!handled && getActivity() instanceof OnPreferenceDisplayDialogCallback) {
handled = ((OnPreferenceDisplayDialogCallback) getActivity())
.onPreferenceDisplayDialog(this, preference);
}
if (handled) {
return;
}
// check if dialog is already showing
if (getRouter().getControllerWithTag(DIALOG_FRAGMENT_TAG) != null) {
return;
}
final PreferenceDialogController f;
if (preference instanceof EditTextPreference) {
f = EditTextPreferenceDialogController.newInstance(preference.getKey());
} else if (preference instanceof ListPreference) {
f = ListPreferenceDialogController.newInstance(preference.getKey());
} else if (preference instanceof MultiSelectListPreference) {
f = MultiSelectListPreferenceDialogController.newInstance(preference.getKey());
} else {
throw new IllegalArgumentException("Tried to display dialog for unknown " +
"preference type. Did you forget to override onDisplayPreferenceDialog()?");
}
f.setTargetController(this);
f.showDialog(getRouter(), DIALOG_FRAGMENT_TAG);
}
/**
* Basically a wrapper for getParentFragment which is v17+. Used by the leanback preference lib.
* @return Fragment to possibly use as a callback
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
public Fragment getCallbackFragment() {
return null;
}
public void scrollToPreference(final String key) {
scrollToPreferenceInternal(null, key);
}
public void scrollToPreference(final Preference preference) {
scrollToPreferenceInternal(preference, null);
}
private void scrollToPreferenceInternal(final Preference preference, final String key) {
final Runnable r = new Runnable() {
@Override
public void run() {
final RecyclerView.Adapter adapter = mList.getAdapter();
if (!(adapter instanceof
PreferenceGroup.PreferencePositionCallback)) {
if (adapter != null) {
throw new IllegalStateException("Adapter must implement "
+ "PreferencePositionCallback");
} else {
// Adapter was set to null, so don't scroll I guess?
return;
}
}
final int position;
if (preference != null) {
position = ((PreferenceGroup.PreferencePositionCallback) adapter)
.getPreferenceAdapterPosition(preference);
} else {
position = ((PreferenceGroup.PreferencePositionCallback) adapter)
.getPreferenceAdapterPosition(key);
}
if (position != RecyclerView.NO_POSITION) {
mList.scrollToPosition(position);
} else {
// Item not found, wait for an update and try again
adapter.registerAdapterDataObserver(
new ScrollToPreferenceObserver(adapter, mList, preference, key));
}
}
};
if (mList == null) {
mSelectPreferenceRunnable = r;
} else {
r.run();
}
}
private static class ScrollToPreferenceObserver extends RecyclerView.AdapterDataObserver {
private final RecyclerView.Adapter mAdapter;
private final RecyclerView mList;
private final Preference mPreference;
private final String mKey;
public ScrollToPreferenceObserver(RecyclerView.Adapter adapter, RecyclerView list,
Preference preference, String key) {
mAdapter = adapter;
mList = list;
mPreference = preference;
mKey = key;
}
private void scrollToPreference() {
mAdapter.unregisterAdapterDataObserver(this);
final int position;
if (mPreference != null) {
position = ((PreferenceGroup.PreferencePositionCallback) mAdapter)
.getPreferenceAdapterPosition(mPreference);
} else {
position = ((PreferenceGroup.PreferencePositionCallback) mAdapter)
.getPreferenceAdapterPosition(mKey);
}
if (position != RecyclerView.NO_POSITION) {
mList.scrollToPosition(position);
}
}
@Override
public void onChanged() {
scrollToPreference();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
scrollToPreference();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
scrollToPreference();
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
scrollToPreference();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
scrollToPreference();
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
scrollToPreference();
}
}
private class DividerDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private int mDividerHeight;
private boolean mAllowDividerAfterLastItem = true;
DividerDecoration() {
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
return;
}
final int childCount = parent.getChildCount();
final int width = parent.getWidth();
for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
final View view = parent.getChildAt(childViewIndex);
if (shouldDrawDividerBelow(view, parent)) {
int top = (int) view.getY() + view.getHeight();
mDivider.setBounds(0, top, width, top + mDividerHeight);
mDivider.draw(c);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
if (shouldDrawDividerBelow(view, parent)) {
outRect.bottom = mDividerHeight;
}
}
private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
final boolean dividerAllowedBelow = holder instanceof PreferenceViewHolder
&& ((PreferenceViewHolder) holder).isDividerAllowedBelow();
if (!dividerAllowedBelow) {
return false;
}
boolean nextAllowed = mAllowDividerAfterLastItem;
int index = parent.indexOfChild(view);
if (index < parent.getChildCount() - 1) {
final View nextView = parent.getChildAt(index + 1);
final RecyclerView.ViewHolder nextHolder = parent.getChildViewHolder(nextView);
nextAllowed = nextHolder instanceof PreferenceViewHolder
&& ((PreferenceViewHolder) nextHolder).isDividerAllowedAbove();
}
return nextAllowed;
}
public void setDivider(Drawable divider) {
if (divider != null) {
mDividerHeight = divider.getIntrinsicHeight();
} else {
mDividerHeight = 0;
}
mDivider = divider;
mList.invalidateItemDecorations();
}
public void setDividerHeight(int dividerHeight) {
mDividerHeight = dividerHeight;
mList.invalidateItemDecorations();
}
public void setAllowDividerAfterLastItem(boolean allowDividerAfterLastItem) {
mAllowDividerAfterLastItem = allowDividerAfterLastItem;
}
}
}

View File

@ -1,363 +0,0 @@
/*
* Copyright (C) 2015 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 androidx.preference;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.*;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.appcompat.app.AlertDialog;
import com.bluelinelabs.conductor.Controller;
import com.bluelinelabs.conductor.RestoreViewOnCreateController;
import com.bluelinelabs.conductor.Router;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
/**
* Abstract base class which presents a dialog associated with a
* {@link androidx.preference.DialogPreference}. Since the preference object may
* not be available during fragment re-creation, the necessary information for displaying the dialog
* is read once during the initial call to {@link #onCreate(Bundle)} and saved/restored in the saved
* instance state. Custom subclasses should also follow this pattern.
*/
public abstract class PreferenceDialogController extends RestoreViewOnCreateController implements
DialogInterface.OnClickListener {
protected static final String ARG_KEY = "key";
private static final String SAVE_DIALOG_STATE_TAG = "android:savedDialogState";
private static final String SAVE_STATE_TITLE = "PreferenceDialogController.title";
private static final String SAVE_STATE_POSITIVE_TEXT = "PreferenceDialogController.positiveText";
private static final String SAVE_STATE_NEGATIVE_TEXT = "PreferenceDialogController.negativeText";
private static final String SAVE_STATE_MESSAGE = "PreferenceDialogController.message";
private static final String SAVE_STATE_LAYOUT = "PreferenceDialogController.layout";
private static final String SAVE_STATE_ICON = "PreferenceDialogController.icon";
private DialogPreference mPreference;
private CharSequence mDialogTitle;
private CharSequence mPositiveButtonText;
private CharSequence mNegativeButtonText;
private CharSequence mDialogMessage;
private @LayoutRes int mDialogLayoutRes;
private BitmapDrawable mDialogIcon;
/** Which button was clicked. */
private int mWhichButtonClicked;
private Dialog dialog;
private boolean dismissed;
@NonNull
@Override
final protected View onCreateView(@NonNull LayoutInflater inflater,
@NonNull ViewGroup container,
@Nullable Bundle savedViewState) {
onCreate(savedViewState);
dialog = onCreateDialog(savedViewState);
//noinspection ConstantConditions
dialog.setOwnerActivity(getActivity());
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
PreferenceDialogController.this.dismissDialog();
}
});
if (savedViewState != null) {
Bundle dialogState = savedViewState.getBundle(SAVE_DIALOG_STATE_TAG);
if (dialogState != null) {
dialog.onRestoreInstanceState(dialogState);
}
}
return new View(getActivity());//stub view
}
public void onCreate(Bundle savedInstanceState) {
final Controller rawController = getTargetController();
if (!(rawController instanceof DialogPreference.TargetFragment)) {
throw new IllegalStateException("Target controller must implement TargetFragment" +
" interface");
}
final DialogPreference.TargetFragment controller =
(DialogPreference.TargetFragment) rawController;
final String key = getArgs().getString(ARG_KEY);
if (savedInstanceState == null) {
mPreference = (DialogPreference) controller.findPreference(key);
mDialogTitle = mPreference.getDialogTitle();
mPositiveButtonText = mPreference.getPositiveButtonText();
mNegativeButtonText = mPreference.getNegativeButtonText();
mDialogMessage = mPreference.getDialogMessage();
mDialogLayoutRes = mPreference.getDialogLayoutResource();
final Drawable icon = mPreference.getDialogIcon();
if (icon == null || icon instanceof BitmapDrawable) {
mDialogIcon = (BitmapDrawable) icon;
} else {
final Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
icon.draw(canvas);
mDialogIcon = new BitmapDrawable(getResources(), bitmap);
}
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putCharSequence(SAVE_STATE_TITLE, mDialogTitle);
outState.putCharSequence(SAVE_STATE_POSITIVE_TEXT, mPositiveButtonText);
outState.putCharSequence(SAVE_STATE_NEGATIVE_TEXT, mNegativeButtonText);
outState.putCharSequence(SAVE_STATE_MESSAGE, mDialogMessage);
outState.putInt(SAVE_STATE_LAYOUT, mDialogLayoutRes);
if (mDialogIcon != null) {
outState.putParcelable(SAVE_STATE_ICON, mDialogIcon.getBitmap());
}
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDialogTitle = savedInstanceState.getCharSequence(SAVE_STATE_TITLE);
mPositiveButtonText = savedInstanceState.getCharSequence(SAVE_STATE_POSITIVE_TEXT);
mNegativeButtonText = savedInstanceState.getCharSequence(SAVE_STATE_NEGATIVE_TEXT);
mDialogMessage = savedInstanceState.getCharSequence(SAVE_STATE_MESSAGE);
mDialogLayoutRes = savedInstanceState.getInt(SAVE_STATE_LAYOUT, 0);
final Bitmap bitmap = savedInstanceState.getParcelable(SAVE_STATE_ICON);
if (bitmap != null) {
mDialogIcon = new BitmapDrawable(getResources(), bitmap);
}
}
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Context context = getActivity();
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(mDialogTitle)
.setIcon(mDialogIcon)
.setPositiveButton(mPositiveButtonText, this)
.setNegativeButton(mNegativeButtonText, this);
View contentView = onCreateDialogView(context);
if (contentView != null) {
onBindDialogView(contentView);
builder.setView(contentView);
} else {
builder.setMessage(mDialogMessage);
}
onPrepareDialogBuilder(builder);
// Create the dialog
final Dialog dialog = builder.create();
if (needInputMethod()) {
requestInputMethod(dialog);
}
return dialog;
}
@Override
protected void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
super.onSaveViewState(view, outState);
Bundle dialogState = dialog.onSaveInstanceState();
outState.putBundle(SAVE_DIALOG_STATE_TAG, dialogState);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
dialog.show();
}
@Override
protected void onDetach(@NonNull View view) {
super.onDetach(view);
dialog.hide();
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
dialog.setOnDismissListener(null);
dialog.dismiss();
dialog = null;
mPreference = null;
}
/**
* Display the dialog, create a transaction and pushing the controller.
*
* @param router The router on which the transaction will be applied
*/
public void showDialog(@NonNull Router router) {
showDialog(router, null);
}
/**
* Display the dialog, create a transaction and pushing the controller.
*
* @param router The router on which the transaction will be applied
* @param tag The tag for this controller
*/
public void showDialog(@NonNull Router router, @Nullable String tag) {
dismissed = false;
router.pushController(RouterTransaction.with(this)
.pushChangeHandler(new SimpleSwapChangeHandler(false))
.popChangeHandler(new SimpleSwapChangeHandler(false))
.tag(tag));
}
/**
* Dismiss the dialog and pop this controller
*/
public void dismissDialog() {
if (dismissed) {
return;
}
onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
getRouter().popController(this);
dismissed = true;
}
@Nullable
protected Dialog getDialog() {
return dialog;
}
/**
* Get the preference that requested this dialog. Available after {@link #onCreate(Bundle)} has
* been called on the {@link PreferenceFragmentCompat} which launched this dialog.
*
* @return The {@link DialogPreference} associated with this
* dialog.
*/
public DialogPreference getPreference() {
if (mPreference == null) {
final String key = getArgs().getString(ARG_KEY);
final DialogPreference.TargetFragment controller =
(DialogPreference.TargetFragment) getTargetController();
mPreference = (DialogPreference) controller.findPreference(key);
}
return mPreference;
}
/**
* Prepares the dialog builder to be shown when the preference is clicked.
* Use this to set custom properties on the dialog.
* <p>
* Do not {@link AlertDialog.Builder#create()} or
* {@link AlertDialog.Builder#show()}.
*/
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
}
/**
* Returns whether the preference needs to display a soft input method when the dialog
* is displayed. Default is false. Subclasses should override this method if they need
* the soft input method brought up automatically.
*
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
protected boolean needInputMethod() {
return false;
}
/**
* Sets the required flags on the dialog window to enable input method window to show up.
*/
private void requestInputMethod(Dialog dialog) {
Window window = dialog.getWindow();
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
/**
* Creates the content view for the dialog (if a custom content view is
* required). By default, it inflates the dialog layout resource if it is
* set.
*
* @return The content View for the dialog.
* @see DialogPreference#setLayoutResource(int)
*/
protected View onCreateDialogView(Context context) {
final int resId = mDialogLayoutRes;
if (resId == 0) {
return null;
}
LayoutInflater inflater = LayoutInflater.from(context);
return inflater.inflate(resId, null);
}
/**
* Binds views in the content View of the dialog to data.
* <p>
* Make sure to call through to the superclass implementation.
*
* @param view The content View of the dialog, if it is custom.
*/
protected void onBindDialogView(View view) {
View dialogMessageView = view.findViewById(android.R.id.message);
if (dialogMessageView != null) {
final CharSequence message = mDialogMessage;
int newVisibility = View.GONE;
if (!TextUtils.isEmpty(message)) {
if (dialogMessageView instanceof TextView) {
((TextView) dialogMessageView).setText(message);
}
newVisibility = View.VISIBLE;
}
if (dialogMessageView.getVisibility() != newVisibility) {
dialogMessageView.setVisibility(newVisibility);
}
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
mWhichButtonClicked = which;
}
public abstract void onDialogClosed(boolean positiveResult);
}

View File

@ -1 +1 @@
include ':app', ':j2k-preference'
include ':app'