| /* |
| * Copyright 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.car.ui.preference; |
| |
| import static com.android.car.ui.preference.PreferenceDialogFragment.ARG_KEY; |
| |
| import android.os.Bundle; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.fragment.app.Fragment; |
| import androidx.preference.DialogPreference; |
| import androidx.preference.ListPreference; |
| import androidx.preference.Preference; |
| |
| import com.android.car.ui.R; |
| import com.android.car.ui.baselayout.Insets; |
| import com.android.car.ui.baselayout.InsetsChangedListener; |
| import com.android.car.ui.core.CarUi; |
| import com.android.car.ui.recyclerview.CarUiContentListItem; |
| import com.android.car.ui.recyclerview.CarUiListItem; |
| import com.android.car.ui.recyclerview.CarUiListItemAdapter; |
| import com.android.car.ui.recyclerview.CarUiRecyclerView; |
| import com.android.car.ui.toolbar.Toolbar; |
| import com.android.car.ui.toolbar.ToolbarController; |
| import com.android.car.ui.utils.CarUiUtils; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * A fragment that provides a layout with a list of options associated with a {@link |
| * ListPreference}. |
| */ |
| public class ListPreferenceFragment extends Fragment implements InsetsChangedListener { |
| |
| private static final String ARG_FULLSCREEN = "fullscreen"; |
| |
| private ListPreference mPreference; |
| private CarUiContentListItem mSelectedItem; |
| private int mSelectedIndex = -1; |
| private boolean mFullScreen; |
| |
| /** |
| * Returns a new instance of {@link ListPreferenceFragment} for the {@link ListPreference} with |
| * the given {@code key}. |
| */ |
| @NonNull |
| static ListPreferenceFragment newInstance(String key, boolean fullScreen) { |
| ListPreferenceFragment fragment = new ListPreferenceFragment(); |
| Bundle b = new Bundle(/* capacity= */ 1); |
| b.putString(ARG_KEY, key); |
| b.putBoolean(ARG_FULLSCREEN, fullScreen); |
| fragment.setArguments(b); |
| return fragment; |
| } |
| |
| @Nullable |
| @Override |
| public View onCreateView( |
| @NonNull LayoutInflater inflater, @Nullable ViewGroup container, |
| @Nullable Bundle savedInstanceState) { |
| if (CarUi.getToolbar(getActivity()) == null) { |
| return inflater.inflate(R.layout.car_ui_list_preference_with_toolbar, container, false); |
| } else { |
| return inflater.inflate(R.layout.car_ui_list_preference, container, false); |
| } |
| } |
| |
| @Override |
| public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { |
| super.onViewCreated(view, savedInstanceState); |
| final CarUiRecyclerView carUiRecyclerView = CarUiUtils.requireViewByRefId(view, R.id.list); |
| mFullScreen = requireArguments().getBoolean(ARG_FULLSCREEN, true); |
| ToolbarController toolbar = mFullScreen ? CarUi.getToolbar(getActivity()) : null; |
| |
| // TODO(b/150230923) remove the code for the old toolbar height change when apps are ready |
| if (toolbar == null) { |
| Toolbar toolbarView = CarUiUtils.findViewByRefId(view, R.id.toolbar); |
| toolbar = toolbarView; |
| |
| if (toolbarView != null) { |
| carUiRecyclerView.setPadding(0, toolbarView.getHeight(), 0, 0); |
| toolbarView.registerToolbarHeightChangeListener(newHeight -> { |
| if (carUiRecyclerView.getPaddingTop() == newHeight) { |
| return; |
| } |
| |
| int oldHeight = carUiRecyclerView.getPaddingTop(); |
| carUiRecyclerView.setPadding(0, newHeight, 0, 0); |
| carUiRecyclerView.scrollBy(0, oldHeight - newHeight); |
| }); |
| } |
| } |
| |
| carUiRecyclerView.setClipToPadding(false); |
| mPreference = getListPreference(); |
| if (toolbar != null) { |
| toolbar.setTitle(mPreference.getTitle()); |
| toolbar.setState(Toolbar.State.SUBPAGE); |
| } |
| |
| CharSequence[] entries = mPreference.getEntries(); |
| CharSequence[] entryValues = mPreference.getEntryValues(); |
| |
| if (entries == null || entryValues == null) { |
| throw new IllegalStateException( |
| "ListPreference requires an entries array and an entryValues array."); |
| } |
| |
| if (entries.length != entryValues.length) { |
| throw new IllegalStateException( |
| "ListPreference entries array length does not match entryValues array length."); |
| } |
| |
| mSelectedIndex = mPreference.findIndexOfValue(mPreference.getValue()); |
| List<CarUiListItem> listItems = new ArrayList<>(); |
| CarUiListItemAdapter adapter = new CarUiListItemAdapter(listItems); |
| |
| for (int i = 0; i < entries.length; i++) { |
| String entry = entries[i].toString(); |
| CarUiContentListItem item = new CarUiContentListItem( |
| CarUiContentListItem.Action.RADIO_BUTTON); |
| item.setTitle(entry); |
| |
| if (i == mSelectedIndex) { |
| item.setChecked(true); |
| mSelectedItem = item; |
| } |
| |
| item.setOnCheckedChangeListener((listItem, isChecked) -> { |
| if (mSelectedItem != null) { |
| mSelectedItem.setChecked(false); |
| adapter.notifyItemChanged(listItems.indexOf(mSelectedItem)); |
| } |
| mSelectedItem = listItem; |
| mSelectedIndex = listItems.indexOf(mSelectedItem); |
| }); |
| |
| listItems.add(item); |
| } |
| |
| carUiRecyclerView.setAdapter(adapter); |
| } |
| |
| @Override |
| public void onStart() { |
| super.onStart(); |
| Insets insets = CarUi.getInsets(getActivity()); |
| if (insets != null) { |
| onCarUiInsetsChanged(insets); |
| } |
| } |
| |
| @Override |
| public void onStop() { |
| super.onStop(); |
| updatePreference(); |
| } |
| |
| private void updatePreference() { |
| if (mSelectedIndex >= 0 && mPreference != null) { |
| String entryValue = mPreference.getEntryValues()[mSelectedIndex].toString(); |
| |
| if (mPreference.callChangeListener(entryValue)) { |
| mPreference.setValue(entryValue); |
| } |
| } |
| } |
| |
| private ListPreference getListPreference() { |
| String key = requireArguments().getString(ARG_KEY); |
| DialogPreference.TargetFragment fragment = |
| (DialogPreference.TargetFragment) getTargetFragment(); |
| |
| if (key == null) { |
| throw new IllegalStateException( |
| "ListPreference key not found in Fragment arguments"); |
| } |
| |
| if (fragment == null) { |
| throw new IllegalStateException( |
| "Target fragment must be registered before displaying ListPreference " |
| + "screen."); |
| } |
| |
| Preference preference = fragment.findPreference(key); |
| |
| if (!(preference instanceof ListPreference)) { |
| throw new IllegalStateException( |
| "Cannot use ListPreferenceFragment with a preference that is not of type " |
| + "ListPreference"); |
| } |
| |
| return (ListPreference) preference; |
| } |
| |
| @Override |
| public void onCarUiInsetsChanged(@NonNull Insets insets) { |
| if (!mFullScreen) { |
| return; |
| } |
| View view = requireView(); |
| CarUiUtils.requireViewByRefId(view, R.id.list) |
| .setPadding(0, insets.getTop(), 0, insets.getBottom()); |
| view.setPadding(insets.getLeft(), 0, insets.getRight(), 0); |
| } |
| } |