• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.intentresolver.contentpreview;
18 
19 import static android.content.ContentProvider.getUserIdFromUri;
20 
21 import android.animation.ObjectAnimator;
22 import android.animation.ValueAnimator;
23 import android.content.res.Resources;
24 import android.graphics.Bitmap;
25 import android.net.Uri;
26 import android.os.UserHandle;
27 import android.util.Log;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.view.ViewStub;
32 import android.view.animation.DecelerateInterpolator;
33 
34 import androidx.annotation.LayoutRes;
35 
36 import com.android.intentresolver.R;
37 import com.android.intentresolver.flags.FeatureFlagRepository;
38 import com.android.intentresolver.flags.Flags;
39 import com.android.intentresolver.widget.ActionRow;
40 import com.android.intentresolver.widget.RoundedRectImageView;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 abstract class ContentPreviewUi {
46     private static final int IMAGE_FADE_IN_MILLIS = 150;
47     static final String TAG = "ChooserPreview";
48 
49     @ContentPreviewType
getType()50     public abstract int getType();
51 
display( Resources resources, LayoutInflater layoutInflater, ViewGroup parent)52     public abstract ViewGroup display(
53             Resources resources, LayoutInflater layoutInflater, ViewGroup parent);
54 
getActionRowLayout(FeatureFlagRepository featureFlagRepository)55     protected static int getActionRowLayout(FeatureFlagRepository featureFlagRepository) {
56         return featureFlagRepository.isEnabled(Flags.SHARESHEET_CUSTOM_ACTIONS)
57                 ? R.layout.scrollable_chooser_action_row
58                 : R.layout.chooser_action_row;
59     }
60 
inflateActionRow(ViewGroup parent, @LayoutRes int actionRowLayout)61     protected static ActionRow inflateActionRow(ViewGroup parent, @LayoutRes int actionRowLayout) {
62         final ViewStub stub = parent.findViewById(com.android.intentresolver.R.id.action_row_stub);
63         if (stub != null) {
64             stub.setLayoutResource(actionRowLayout);
65             stub.inflate();
66         }
67         return parent.findViewById(com.android.internal.R.id.chooser_action_row);
68     }
69 
createActions( List<ActionRow.Action> systemActions, List<ActionRow.Action> customActions, FeatureFlagRepository featureFlagRepository)70     protected static List<ActionRow.Action> createActions(
71             List<ActionRow.Action> systemActions,
72             List<ActionRow.Action> customActions,
73             FeatureFlagRepository featureFlagRepository) {
74         ArrayList<ActionRow.Action> actions =
75                 new ArrayList<>(systemActions.size() + customActions.size());
76         actions.addAll(systemActions);
77         if (featureFlagRepository.isEnabled(Flags.SHARESHEET_CUSTOM_ACTIONS)) {
78             actions.addAll(customActions);
79         }
80         return actions;
81     }
82 
83     /**
84      * Indicate if the incoming content URI should be allowed.
85      *
86      * @param uri the uri to test
87      * @return true if the URI is allowed for content preview
88      */
validForContentPreview(Uri uri)89     protected static boolean validForContentPreview(Uri uri) throws SecurityException {
90         if (uri == null) {
91             return false;
92         }
93         int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT);
94         if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) {
95             Log.e(ContentPreviewUi.TAG, "dropped invalid content URI belonging to user " + userId);
96             return false;
97         }
98         return true;
99     }
100 
updateViewWithImage(RoundedRectImageView imageView, Bitmap image)101     protected static void updateViewWithImage(RoundedRectImageView imageView, Bitmap image) {
102         if (image == null) {
103             imageView.setVisibility(View.GONE);
104             return;
105         }
106         imageView.setVisibility(View.VISIBLE);
107         imageView.setAlpha(0.0f);
108         imageView.setImageBitmap(image);
109 
110         ValueAnimator fadeAnim = ObjectAnimator.ofFloat(imageView, "alpha", 0.0f, 1.0f);
111         fadeAnim.setInterpolator(new DecelerateInterpolator(1.0f));
112         fadeAnim.setDuration(IMAGE_FADE_IN_MILLIS);
113         fadeAnim.start();
114     }
115 
displayPayloadReselectionAction( ViewGroup layout, ChooserContentPreviewUi.ActionFactory actionFactory, FeatureFlagRepository featureFlagRepository)116     protected static void displayPayloadReselectionAction(
117             ViewGroup layout,
118             ChooserContentPreviewUi.ActionFactory actionFactory,
119             FeatureFlagRepository featureFlagRepository) {
120         Runnable modifyShareAction = actionFactory.getModifyShareAction();
121         if (modifyShareAction != null && layout != null
122                 && featureFlagRepository.isEnabled(Flags.SHARESHEET_RESELECTION_ACTION)) {
123             View modifyShareView = layout.findViewById(R.id.reselection_action);
124             if (modifyShareView != null) {
125                 modifyShareView.setVisibility(View.VISIBLE);
126                 modifyShareView.setOnClickListener(view -> modifyShareAction.run());
127             }
128         }
129     }
130 }
131