blob: f94794501922d36317c18f0f3986126fb8985837 [file] [log] [blame]
/*
* 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.car.media.common;
import android.annotation.NonNull;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.car.widget.PagedListView;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.car.media.common.source.MediaSource;
import com.android.car.media.common.source.MediaSourceViewModel;
import com.android.car.media.common.source.MediaSourcesLiveData;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link Fragment} that implements the app selection UI. It is typically created by a
* {@link MediaAppSelectorWidget} widget that shows the current media source (stored as
* {@link #mSelectorWidget}. To ensure visual coherence, the UI of the fragment also shows a
* {@link MediaAppSelectorWidget} widget, but this one is in "display only" mode as tapping it
* closes the fragment rather than opening a new one.
*/
public class AppSelectionFragment extends DialogFragment {
private static final String ORIGIN_SOURCE_PACKAGE_KEY = "origin_source_package_key";
private static final String FULL_SCREEN_KEY = "full_screen_key";
/** The widget that opened this fragment. */
private final MediaAppSelectorWidget mSelectorWidget;
private String mOriginSourcePackage;
private boolean mFullScreenDialog;
/** The widget contained by this fragment UI to display the current source. */
private MediaAppSelectorWidget mDisplayWidget;
/**
* Creates a new {@link AppSelectionFragment}.
* @param selectorWidget the widget that is opening this fragment
* @param originSourcePackage the media source package shown in the selectorWidget.
*/
public static AppSelectionFragment create(MediaAppSelectorWidget selectorWidget,
String originSourcePackage, boolean fullScreenDialog) {
AppSelectionFragment result = new AppSelectionFragment(selectorWidget);
Bundle bundle = new Bundle(1);
bundle.putString(ORIGIN_SOURCE_PACKAGE_KEY, originSourcePackage);
bundle.putBoolean(FULL_SCREEN_KEY, fullScreenDialog);
result.setArguments(bundle);
return result;
}
public AppSelectionFragment() {
this(null);
}
private AppSelectionFragment(MediaAppSelectorWidget selectorWidget) {
mSelectorWidget = selectorWidget;
}
private class AppGridAdapter extends RecyclerView.Adapter<AppItemViewHolder> {
private List<MediaSource> mMediaSources;
/**
* Triggers a refresh of media sources
*/
void updateSources(List<MediaSource> mediaSources) {
mMediaSources = new ArrayList<>(mediaSources);
notifyDataSetChanged();
}
@NonNull
@Override
public AppItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.app_selection_item, parent, false);
return new AppItemViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull AppItemViewHolder vh, int position) {
vh.bind(mMediaSources.get(position));
}
@Override
public int getItemCount() {
return mMediaSources.size();
}
}
private class AppItemViewHolder extends RecyclerView.ViewHolder {
View mAppItem;
ImageView mAppIconView;
TextView mAppNameView;
AppItemViewHolder(View view) {
super(view);
mAppItem = view.findViewById(R.id.app_item);
mAppIconView = mAppItem.findViewById(R.id.app_icon);
mAppNameView = mAppItem.findViewById(R.id.app_name);
}
/**
* Binds a media source to a view
*/
void bind(@NonNull MediaSource mediaSrc) {
mAppItem.setOnClickListener(
v -> {
MediaSourceViewModel model = MediaSourceViewModel.get(
requireActivity().getApplication());
model.setPrimaryMediaSource(mediaSrc);
dismiss();
});
mAppIconView.setImageDrawable(mediaSrc.getPackageIcon());
mAppNameView.setText(mediaSrc.getName());
}
}
@Override
public void dismiss() {
if (mSelectorWidget != null) {
mSelectorWidget.setIsOpen(false);
}
mDisplayWidget.setIsOpen(false);
// TODO(b/122324380) try using a shared element transition instead of this trick.
// The delay is needed to update the arrow in the MediaAppSelectorWidget of this fragment
// before the fragment fades away to reveal the underlying MediaAppSelectorWidget with an
// arrow pointing the other way. Otherwise we end up seeing the arrows pointing in opposite
// directions... Note that in the home screen the widgets are not overlapped.
mDisplayWidget.postDelayed(() -> superDismiss(), 50);
}
private void superDismiss() {
super.dismiss();
}
@Override
public void onStart() {
super.onStart();
if (getDialog() != null) {
getDialog().getWindow().setWindowAnimations(R.style.media_app_selector_animation_fade);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.MediaAppSelectorStyle); // Full screen style.
Bundle args = getArguments();
if (args != null) {
mOriginSourcePackage = args.getString(ORIGIN_SOURCE_PACKAGE_KEY);
mFullScreenDialog = args.getBoolean(FULL_SCREEN_KEY, true);
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_app_selection, container, false);
if (mFullScreenDialog) {
ViewGroup contentView = view.findViewById(R.id.actual_content);
ViewGroup.MarginLayoutParams p =
(ViewGroup.MarginLayoutParams) contentView.getLayoutParams();
p.setMargins(0, 0, 0, 0);
}
int columnNumber = getResources().getInteger(R.integer.num_app_selector_columns);
AppGridAdapter gridAdapter = new AppGridAdapter();
gridAdapter.updateSources(MediaSourcesLiveData.getInstance(getContext()).getList());
mDisplayWidget = view.findViewById(R.id.app_switch_container);
mDisplayWidget.setFragmentOwner(this);
mDisplayWidget.setFragmentActivity(getActivity());
PagedListView gridView = view.findViewById(R.id.apps_grid);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), columnNumber);
gridView.getRecyclerView().setLayoutManager(gridLayoutManager);
gridView.setAdapter(gridAdapter);
return view;
}
}