OSDN Git Service

Remove error slice from Settings in rendering time
[android-x86/packages-apps-Settings.git] / src / com / android / settings / homepage / contextualcards / slices / SliceContextualCardRenderer.java
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.settings.homepage.contextualcards.slices;
18
19 import static android.app.slice.Slice.HINT_ERROR;
20
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.net.Uri;
24 import android.util.ArrayMap;
25 import android.util.ArraySet;
26 import android.util.Log;
27 import android.view.View;
28 import android.widget.Button;
29
30 import androidx.annotation.LayoutRes;
31 import androidx.annotation.VisibleForTesting;
32 import androidx.lifecycle.Lifecycle;
33 import androidx.lifecycle.LifecycleObserver;
34 import androidx.lifecycle.LifecycleOwner;
35 import androidx.lifecycle.LiveData;
36 import androidx.lifecycle.OnLifecycleEvent;
37 import androidx.recyclerview.widget.RecyclerView;
38 import androidx.slice.Slice;
39 import androidx.slice.widget.SliceLiveData;
40
41 import com.android.settings.R;
42 import com.android.settings.homepage.contextualcards.CardContentProvider;
43 import com.android.settings.homepage.contextualcards.ContextualCard;
44 import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
45 import com.android.settings.homepage.contextualcards.ControllerRendererPool;
46
47 import java.util.Map;
48 import java.util.Set;
49
50 /**
51  * Card renderer for {@link ContextualCard} built as slice full card or slice half card.
52  */
53 public class SliceContextualCardRenderer implements ContextualCardRenderer, LifecycleObserver {
54     public static final int VIEW_TYPE_FULL_WIDTH = R.layout.contextual_slice_full_tile;
55     public static final int VIEW_TYPE_HALF_WIDTH = R.layout.contextual_slice_half_tile;
56     public static final int VIEW_TYPE_DEFERRED_SETUP = R.layout.contextual_slice_deferred_setup;
57
58     private static final String TAG = "SliceCardRenderer";
59
60     @VisibleForTesting
61     final Map<Uri, LiveData<Slice>> mSliceLiveDataMap;
62     @VisibleForTesting
63     final Set<RecyclerView.ViewHolder> mFlippedCardSet;
64
65     private final Context mContext;
66     private final LifecycleOwner mLifecycleOwner;
67     private final ControllerRendererPool mControllerRendererPool;
68     private final SliceDeferredSetupCardRendererHelper mDeferredSetupCardHelper;
69     private final SliceFullCardRendererHelper mFullCardHelper;
70     private final SliceHalfCardRendererHelper mHalfCardHelper;
71
72     public SliceContextualCardRenderer(Context context, LifecycleOwner lifecycleOwner,
73             ControllerRendererPool controllerRendererPool) {
74         mContext = context;
75         mLifecycleOwner = lifecycleOwner;
76         mSliceLiveDataMap = new ArrayMap<>();
77         mControllerRendererPool = controllerRendererPool;
78         mFlippedCardSet = new ArraySet<>();
79         mLifecycleOwner.getLifecycle().addObserver(this);
80         mFullCardHelper = new SliceFullCardRendererHelper(context);
81         mHalfCardHelper = new SliceHalfCardRendererHelper(context);
82         mDeferredSetupCardHelper = new SliceDeferredSetupCardRendererHelper(context);
83     }
84
85     @Override
86     public RecyclerView.ViewHolder createViewHolder(View view, @LayoutRes int viewType) {
87         switch (viewType) {
88             case VIEW_TYPE_DEFERRED_SETUP:
89                 return mDeferredSetupCardHelper.createViewHolder(view);
90             case VIEW_TYPE_HALF_WIDTH:
91                 return mHalfCardHelper.createViewHolder(view);
92             default:
93                 return mFullCardHelper.createViewHolder(view);
94         }
95     }
96
97     @Override
98     public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
99         final Uri uri = card.getSliceUri();
100
101         if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
102             Log.w(TAG, "Invalid uri, skipping slice: " + uri);
103             return;
104         }
105
106         LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri);
107
108         if (sliceLiveData == null) {
109             sliceLiveData = SliceLiveData.fromUri(mContext, uri);
110             mSliceLiveDataMap.put(uri, sliceLiveData);
111         }
112
113         sliceLiveData.removeObservers(mLifecycleOwner);
114         sliceLiveData.observe(mLifecycleOwner, slice -> {
115             if (slice == null) {
116                 Log.w(TAG, "Slice is null");
117                 mContext.getContentResolver().notifyChange(CardContentProvider.REFRESH_CARD_URI,
118                         null);
119                 return;
120             }
121
122             if (slice.hasHint(HINT_ERROR)) {
123                 Log.w(TAG, "Slice has HINT_ERROR, skipping rendering. uri=" + slice.getUri());
124                 mSliceLiveDataMap.get(slice.getUri()).removeObservers(mLifecycleOwner);
125                 mContext.getContentResolver().notifyChange(CardContentProvider.REFRESH_CARD_URI,
126                         null);
127                 return;
128             }
129
130             switch (holder.getItemViewType()) {
131                 case VIEW_TYPE_DEFERRED_SETUP:
132                     mDeferredSetupCardHelper.bindView(holder, card, slice);
133                     break;
134                 case VIEW_TYPE_HALF_WIDTH:
135                     mHalfCardHelper.bindView(holder, card, slice);
136                     break;
137                 default:
138                     mFullCardHelper.bindView(holder, card, slice);
139             }
140         });
141
142         switch (holder.getItemViewType()) {
143             case VIEW_TYPE_DEFERRED_SETUP:
144                 // Deferred setup is never dismissible.
145                 break;
146             case VIEW_TYPE_HALF_WIDTH:
147                 initDismissalActions(holder, card);
148                 break;
149             default:
150                 initDismissalActions(holder, card);
151         }
152
153         if (card.isPendingDismiss()) {
154             showDismissalView(holder);
155             mFlippedCardSet.add(holder);
156         }
157     }
158
159     private void initDismissalActions(RecyclerView.ViewHolder holder, ContextualCard card) {
160         final Button btnKeep = holder.itemView.findViewById(R.id.keep);
161         btnKeep.setOnClickListener(v -> {
162             mFlippedCardSet.remove(holder);
163             resetCardView(holder);
164         });
165
166         final Button btnRemove = holder.itemView.findViewById(R.id.remove);
167         btnRemove.setOnClickListener(v -> {
168             mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
169             mFlippedCardSet.remove(holder);
170             resetCardView(holder);
171             mSliceLiveDataMap.get(card.getSliceUri()).removeObservers(mLifecycleOwner);
172         });
173     }
174
175     @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
176     public void onStop() {
177         mFlippedCardSet.stream().forEach(holder -> resetCardView(holder));
178         mFlippedCardSet.clear();
179     }
180
181     private void resetCardView(RecyclerView.ViewHolder holder) {
182         holder.itemView.findViewById(R.id.dismissal_view).setVisibility(View.GONE);
183         getInitialView(holder).setVisibility(View.VISIBLE);
184     }
185
186     private void showDismissalView(RecyclerView.ViewHolder holder) {
187         holder.itemView.findViewById(R.id.dismissal_view).setVisibility(View.VISIBLE);
188         getInitialView(holder).setVisibility(View.INVISIBLE);
189     }
190
191     private View getInitialView(RecyclerView.ViewHolder viewHolder) {
192         if (viewHolder.getItemViewType() == VIEW_TYPE_HALF_WIDTH) {
193             return ((SliceHalfCardRendererHelper.HalfCardViewHolder) viewHolder).content;
194         }
195         return ((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView;
196     }
197 }