1 /*
2  * Copyright 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 androidx.core.app;
18 
19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20 
21 import android.annotation.SuppressLint;
22 import android.app.PendingIntent;
23 import android.app.RemoteAction;
24 import android.graphics.drawable.Icon;
25 import android.os.Build;
26 
27 import androidx.annotation.RequiresApi;
28 import androidx.annotation.RestrictTo;
29 import androidx.core.graphics.drawable.IconCompat;
30 import androidx.core.util.Preconditions;
31 import androidx.versionedparcelable.ParcelField;
32 import androidx.versionedparcelable.VersionedParcelable;
33 import androidx.versionedparcelable.VersionedParcelize;
34 
35 import org.jspecify.annotations.NonNull;
36 
37 /**
38  * Represents a remote action that can be called from another process.  The action can have an
39  * associated visualization including metadata like an icon or title.
40  * <p>
41  * This is a backward-compatible version of {@link RemoteAction}.
42  */
43 @VersionedParcelize(jetifyAs = "android.support.v4.app.RemoteActionCompat")
44 public final class RemoteActionCompat implements VersionedParcelable {
45     /**
46      */
47     @SuppressWarnings("NotNullFieldNotInitialized") // VersionedParceleble inits this field.
48     @RestrictTo(LIBRARY_GROUP)
49     @ParcelField(1)
50     public @NonNull IconCompat mIcon;
51     /**
52      */
53     @SuppressWarnings("NotNullFieldNotInitialized") // VersionedParceleble inits this field.
54     @RestrictTo(LIBRARY_GROUP)
55     @ParcelField(2)
56     public @NonNull CharSequence mTitle;
57     /**
58      */
59     @SuppressWarnings("NotNullFieldNotInitialized") // VersionedParceleble inits this field.
60     @RestrictTo(LIBRARY_GROUP)
61     @ParcelField(3)
62     public @NonNull CharSequence mContentDescription;
63     /**
64      */
65     @SuppressWarnings("NotNullFieldNotInitialized") // VersionedParceleble inits this field.
66     @RestrictTo(LIBRARY_GROUP)
67     @ParcelField(4)
68     public @NonNull PendingIntent mActionIntent;
69     /**
70      */
71     @RestrictTo(LIBRARY_GROUP)
72     @ParcelField(5)
73     public boolean mEnabled;
74     /**
75      */
76     @RestrictTo(LIBRARY_GROUP)
77     @ParcelField(6)
78     public boolean mShouldShowIcon;
79 
RemoteActionCompat(@onNull IconCompat icon, @NonNull CharSequence title, @NonNull CharSequence contentDescription, @NonNull PendingIntent intent)80     public RemoteActionCompat(@NonNull IconCompat icon, @NonNull CharSequence title,
81             @NonNull CharSequence contentDescription, @NonNull PendingIntent intent) {
82         mIcon = Preconditions.checkNotNull(icon);
83         mTitle = Preconditions.checkNotNull(title);
84         mContentDescription = Preconditions.checkNotNull(contentDescription);
85         mActionIntent = Preconditions.checkNotNull(intent);
86         mEnabled = true;
87         mShouldShowIcon = true;
88     }
89 
90     /**
91      * Used for VersionedParcelable.
92      */
93     @RestrictTo(LIBRARY_GROUP)
RemoteActionCompat()94     public RemoteActionCompat() {}
95 
96     /**
97      * Constructs a {@link RemoteActionCompat} using data from {@code other}.
98      */
RemoteActionCompat(@onNull RemoteActionCompat other)99     public RemoteActionCompat(@NonNull RemoteActionCompat other) {
100         Preconditions.checkNotNull(other);
101         mIcon = other.mIcon;
102         mTitle = other.mTitle;
103         mContentDescription = other.mContentDescription;
104         mActionIntent = other.mActionIntent;
105         mEnabled = other.mEnabled;
106         mShouldShowIcon = other.mShouldShowIcon;
107     }
108 
109     /**
110      * Creates an RemoteActionCompat from a RemoteAction.
111      */
112     @RequiresApi(26)
createFromRemoteAction( @onNull RemoteAction remoteAction)113     public static @NonNull RemoteActionCompat createFromRemoteAction(
114             @NonNull RemoteAction remoteAction) {
115         Preconditions.checkNotNull(remoteAction);
116         RemoteActionCompat action = new RemoteActionCompat(IconCompat.createFromIcon(
117                 Api26Impl.getIcon(remoteAction)),
118                 Api26Impl.getTitle(remoteAction),
119                 Api26Impl.getContentDescription(remoteAction),
120                 Api26Impl.getActionIntent(remoteAction));
121         action.setEnabled(Api26Impl.isEnabled(remoteAction));
122         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
123             action.setShouldShowIcon(Api28Impl.shouldShowIcon(remoteAction));
124         }
125         return action;
126     }
127 
128     /**
129      * Sets whether this action is enabled.
130      */
setEnabled(boolean enabled)131     public void setEnabled(boolean enabled) {
132         mEnabled = enabled;
133     }
134 
135     /**
136      * Return whether this action is enabled.
137      */
isEnabled()138     public boolean isEnabled() {
139         return mEnabled;
140     }
141 
142     /**
143      * Sets whether the icon should be shown.
144      */
setShouldShowIcon(boolean shouldShowIcon)145     public void setShouldShowIcon(boolean shouldShowIcon) {
146         mShouldShowIcon = shouldShowIcon;
147     }
148 
149     /**
150      * Return whether the icon should be shown.
151      */
152     @SuppressLint("KotlinPropertyAccess")
shouldShowIcon()153     public boolean shouldShowIcon() {
154         return mShouldShowIcon;
155     }
156 
157     /**
158      * Return an icon representing the action.
159      */
getIcon()160     public @NonNull IconCompat getIcon() {
161         return mIcon;
162     }
163 
164     /**
165      * Return an title representing the action.
166      */
getTitle()167     public @NonNull CharSequence getTitle() {
168         return mTitle;
169     }
170 
171     /**
172      * Return a content description representing the action.
173      */
getContentDescription()174     public @NonNull CharSequence getContentDescription() {
175         return mContentDescription;
176     }
177 
178     /**
179      * Return the action intent.
180      */
getActionIntent()181     public @NonNull PendingIntent getActionIntent() {
182         return mActionIntent;
183     }
184 
185     /**
186      * Convert this compat object to {@link RemoteAction} object.
187      *
188      * @return {@link RemoteAction} object
189      */
190     @SuppressWarnings("deprecation")
191     @RequiresApi(26)
toRemoteAction()192     public @NonNull RemoteAction toRemoteAction() {
193         RemoteAction action = Api26Impl.createRemoteAction(mIcon.toIcon(), mTitle,
194                 mContentDescription, mActionIntent);
195         Api26Impl.setEnabled(action, isEnabled());
196         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
197             Api28Impl.setShouldShowIcon(action, shouldShowIcon());
198         }
199         return action;
200     }
201 
202     @RequiresApi(28)
203     static class Api28Impl {
Api28Impl()204         private Api28Impl() {
205             // This class is not instantiable.
206         }
207 
shouldShowIcon(RemoteAction remoteAction)208         static boolean shouldShowIcon(RemoteAction remoteAction) {
209             return remoteAction.shouldShowIcon();
210         }
211 
setShouldShowIcon(RemoteAction remoteAction, boolean shouldShowIcon)212         static void setShouldShowIcon(RemoteAction remoteAction, boolean shouldShowIcon) {
213             remoteAction.setShouldShowIcon(shouldShowIcon);
214         }
215     }
216 
217     @RequiresApi(26)
218     static class Api26Impl {
Api26Impl()219         private Api26Impl() {
220             // This class is not instantiable.
221         }
222 
getContentDescription(RemoteAction remoteAction)223         static CharSequence getContentDescription(RemoteAction remoteAction) {
224             return remoteAction.getContentDescription();
225         }
226 
getActionIntent(RemoteAction remoteAction)227         static PendingIntent getActionIntent(RemoteAction remoteAction) {
228             return remoteAction.getActionIntent();
229         }
230 
getTitle(RemoteAction remoteAction)231         static CharSequence getTitle(RemoteAction remoteAction) {
232             return remoteAction.getTitle();
233         }
234 
getIcon(RemoteAction remoteAction)235         static Icon getIcon(RemoteAction remoteAction) {
236             return remoteAction.getIcon();
237         }
238 
isEnabled(RemoteAction remoteAction)239         static boolean isEnabled(RemoteAction remoteAction) {
240             return remoteAction.isEnabled();
241         }
242 
createRemoteAction(Icon icon, CharSequence title, CharSequence contentDescription, PendingIntent intent)243         static RemoteAction createRemoteAction(Icon icon, CharSequence title,
244                 CharSequence contentDescription, PendingIntent intent) {
245             return new RemoteAction(icon, title, contentDescription, intent);
246         }
247 
setEnabled(RemoteAction remoteAction, boolean enabled)248         static void setEnabled(RemoteAction remoteAction, boolean enabled) {
249             remoteAction.setEnabled(enabled);
250         }
251     }
252 }
253