• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.car.projection;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.SystemApi;
24 import android.car.annotation.AddedInOrBefore;
25 import android.os.Bundle;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 
29 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
30 import com.android.car.internal.util.IntArray;
31 
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.List;
37 
38 /**
39  * This class encapsulates information about projection status and connected mobile devices.
40  *
41  * <p>Since the number of connected devices expected to be small we include information about
42  * connected devices in every status update.
43  *
44  * @hide
45  */
46 @SystemApi
47 public final class ProjectionStatus implements Parcelable {
48     /** This state indicates that projection is not actively running and no compatible mobile
49      * devices available. */
50     @AddedInOrBefore(majorVersion = 33)
51     public static final int PROJECTION_STATE_INACTIVE = 0;
52 
53     /** At least one phone connected and ready to project. */
54     @AddedInOrBefore(majorVersion = 33)
55     public static final int PROJECTION_STATE_READY_TO_PROJECT = 1;
56 
57     /** Projecting in the foreground */
58     @AddedInOrBefore(majorVersion = 33)
59     public static final int PROJECTION_STATE_ACTIVE_FOREGROUND = 2;
60 
61     /** Projection is running in the background */
62     @AddedInOrBefore(majorVersion = 33)
63     public static final int PROJECTION_STATE_ACTIVE_BACKGROUND = 3;
64 
65     private static final int PROJECTION_STATE_MAX = PROJECTION_STATE_ACTIVE_BACKGROUND;
66 
67     /** This status is used when projection is not actively running */
68     @AddedInOrBefore(majorVersion = 33)
69     public static final int PROJECTION_TRANSPORT_NONE = 0;
70 
71     /** This status is used when projection is not actively running */
72     @AddedInOrBefore(majorVersion = 33)
73     public static final int PROJECTION_TRANSPORT_USB = 1;
74 
75     /** This status is used when projection is not actively running */
76     @AddedInOrBefore(majorVersion = 33)
77     public static final int PROJECTION_TRANSPORT_WIFI = 2;
78 
79     private static final int PROJECTION_TRANSPORT_MAX = PROJECTION_TRANSPORT_WIFI;
80 
81     /** @hide */
82     @IntDef(value = {
83             PROJECTION_TRANSPORT_NONE,
84             PROJECTION_TRANSPORT_USB,
85             PROJECTION_TRANSPORT_WIFI,
86     })
87     @Retention(RetentionPolicy.SOURCE)
88     public @interface ProjectionTransport {}
89 
90     /** @hide */
91     @IntDef(value = {
92             PROJECTION_STATE_INACTIVE,
93             PROJECTION_STATE_READY_TO_PROJECT,
94             PROJECTION_STATE_ACTIVE_FOREGROUND,
95             PROJECTION_STATE_ACTIVE_BACKGROUND,
96     })
97     @Retention(RetentionPolicy.SOURCE)
98     public @interface ProjectionState {}
99 
100     private final String mPackageName;
101     private final int mState;
102     private final int mTransport;
103     private final List<MobileDevice> mConnectedMobileDevices;
104     private final Bundle mExtras;
105 
106     /** Creator for this class. Required to have in parcelable implementations. */
107     @AddedInOrBefore(majorVersion = 33)
108     public static final Creator<ProjectionStatus> CREATOR = new Creator<ProjectionStatus>() {
109         @Override
110         public ProjectionStatus createFromParcel(Parcel source) {
111             return new ProjectionStatus(source);
112         }
113 
114         @Override
115         public ProjectionStatus[] newArray(int size) {
116             return new ProjectionStatus[size];
117         }
118     };
119 
ProjectionStatus(Builder builder)120     private ProjectionStatus(Builder builder) {
121         mPackageName = builder.mPackageName;
122         mState = builder.mState;
123         mTransport = builder.mTransport;
124         mConnectedMobileDevices = new ArrayList<>(builder.mMobileDevices);
125         mExtras = builder.mExtras == null ? null : new Bundle(builder.mExtras);
126     }
127 
ProjectionStatus(Parcel source)128     private ProjectionStatus(Parcel source) {
129         mPackageName = source.readString();
130         mState = source.readInt();
131         mTransport = source.readInt();
132         mExtras = source.readBundle(getClass().getClassLoader());
133         mConnectedMobileDevices = source.createTypedArrayList(MobileDevice.CREATOR);
134     }
135 
136     /** Parcelable implementation */
137     @Override
138     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
139     @AddedInOrBefore(majorVersion = 33)
describeContents()140     public int describeContents() {
141         return 0;
142     }
143 
144     @Override
145     @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)146     public void writeToParcel(Parcel dest, int flags) {
147         dest.writeString(mPackageName);
148         dest.writeInt(mState);
149         dest.writeInt(mTransport);
150         dest.writeBundle(mExtras);
151         dest.writeTypedList(mConnectedMobileDevices);
152     }
153 
154     /** Returns projection state which could be one of the constants starting with
155      * {@code #PROJECTION_STATE_}.
156      */
157     @AddedInOrBefore(majorVersion = 33)
getState()158     public @ProjectionState int getState() {
159         return mState;
160     }
161 
162     /** Returns package name of the projection receiver app. */
163     @AddedInOrBefore(majorVersion = 33)
getPackageName()164     public @NonNull String getPackageName() {
165         return mPackageName;
166     }
167 
168     /** Returns extra information provided by projection receiver app */
169     @AddedInOrBefore(majorVersion = 33)
getExtras()170     public @NonNull Bundle getExtras() {
171         return mExtras == null ? new Bundle() : new Bundle(mExtras);
172     }
173 
174     /** Returns true if currently projecting either in the foreground or in the background. */
175     @AddedInOrBefore(majorVersion = 33)
isActive()176     public boolean isActive() {
177         return mState == PROJECTION_STATE_ACTIVE_BACKGROUND
178                 || mState == PROJECTION_STATE_ACTIVE_FOREGROUND;
179     }
180 
181     /** Returns transport which is used for active projection or
182      * {@link #PROJECTION_TRANSPORT_NONE} if projection is not running.
183      */
184     @AddedInOrBefore(majorVersion = 33)
getTransport()185     public @ProjectionTransport int getTransport() {
186         return mTransport;
187     }
188 
189     /** Returns a list of currently connected mobile devices. */
190     @AddedInOrBefore(majorVersion = 33)
getConnectedMobileDevices()191     public @NonNull List<MobileDevice> getConnectedMobileDevices() {
192         return new ArrayList<>(mConnectedMobileDevices);
193     }
194 
195     /**
196      * Returns new {@link Builder} instance.
197      *
198      * @param packageName package name that will be associated with this status
199      * @param state current projection state, must be one of the {@code PROJECTION_STATE_*}
200      */
201     @NonNull
202     @AddedInOrBefore(majorVersion = 33)
builder(String packageName, @ProjectionState int state)203     public static Builder builder(String packageName, @ProjectionState int state) {
204         return new Builder(packageName, state);
205     }
206 
207     /** Builder class for {@link ProjectionStatus} */
208     public static final class Builder {
209         private final int mState;
210         private final String mPackageName;
211         private int mTransport = PROJECTION_TRANSPORT_NONE;
212         private List<MobileDevice> mMobileDevices = new ArrayList<>();
213         private Bundle mExtras;
214 
Builder(String packageName, @ProjectionState int state)215         private Builder(String packageName, @ProjectionState int state) {
216             if (packageName == null) {
217                 throw new IllegalArgumentException("Package name can't be null");
218             }
219             if (state < 0 || state > PROJECTION_STATE_MAX) {
220                 throw new IllegalArgumentException("Invalid projection state: " + state);
221             }
222             mPackageName = packageName;
223             mState = state;
224         }
225 
226         /**
227          * Sets the transport which is used for currently projecting phone if any.
228          *
229          * @param transport transport of current projection, must be one of the
230          * {@code PROJECTION_TRANSPORT_*}
231          */
232         @AddedInOrBefore(majorVersion = 33)
setProjectionTransport(@rojectionTransport int transport)233         public @NonNull Builder setProjectionTransport(@ProjectionTransport int transport) {
234             checkProjectionTransport(transport);
235             mTransport = transport;
236             return this;
237         }
238 
239         /**
240          * Add connected mobile device
241          *
242          * @param mobileDevice connected mobile device
243          * @return this builder
244          */
245         @AddedInOrBefore(majorVersion = 33)
addMobileDevice(MobileDevice mobileDevice)246         public @NonNull Builder addMobileDevice(MobileDevice mobileDevice) {
247             mMobileDevices.add(mobileDevice);
248             return this;
249         }
250 
251         /**
252          * Add extra information.
253          *
254          * @param extras may contain an extra information that can be passed from the projection
255          * app to the projection status listeners
256          * @return this builder
257          */
258         @AddedInOrBefore(majorVersion = 33)
setExtras(Bundle extras)259         public @NonNull Builder setExtras(Bundle extras) {
260             mExtras = extras;
261             return this;
262         }
263 
264         /** Creates {@link ProjectionStatus} object. */
265         @AddedInOrBefore(majorVersion = 33)
build()266         public ProjectionStatus build() {
267             return new ProjectionStatus(this);
268         }
269     }
270 
checkProjectionTransport(@rojectionTransport int transport)271     private static void checkProjectionTransport(@ProjectionTransport int transport) {
272         if (transport < 0 || transport > PROJECTION_TRANSPORT_MAX) {
273             throw new IllegalArgumentException("Invalid projection transport: " + transport);
274         }
275     }
276 
277     @Override
toString()278     public String toString() {
279         return "ProjectionStatus{"
280                 + "mPackageName='" + mPackageName + '\''
281                 + ", mState=" + mState
282                 + ", mTransport=" + mTransport
283                 + ", mConnectedMobileDevices=" + mConnectedMobileDevices
284                 + (mExtras != null ? " (has extras)" : "")
285                 + '}';
286     }
287 
288     /** Class that represents information about connected mobile device. */
289     public static final class MobileDevice implements Parcelable {
290         private final int mId;
291         private final String mName;
292         private final int[] mAvailableTransports;
293         private final boolean mProjecting;
294         private final Bundle mExtras;
295 
296         /** Creator for this class. Required to have in parcelable implementations. */
297         @AddedInOrBefore(majorVersion = 33)
298         public static final Creator<MobileDevice> CREATOR = new Creator<MobileDevice>() {
299             @Override
300             public MobileDevice createFromParcel(Parcel source) {
301                 return new MobileDevice(source);
302             }
303 
304             @Override
305             public MobileDevice[] newArray(int size) {
306                 return new MobileDevice[size];
307             }
308         };
309 
MobileDevice(Builder builder)310         private MobileDevice(Builder builder) {
311             mId = builder.mId;
312             mName = builder.mName;
313             mAvailableTransports = builder.mAvailableTransports.toArray();
314             mProjecting = builder.mProjecting;
315             mExtras = builder.mExtras == null ? null : new Bundle(builder.mExtras);
316         }
317 
MobileDevice(Parcel source)318         private MobileDevice(Parcel source) {
319             mId = source.readInt();
320             mName = source.readString();
321             mAvailableTransports = source.createIntArray();
322             mProjecting = source.readBoolean();
323             mExtras = source.readBundle(getClass().getClassLoader());
324         }
325 
326         @Override
327         @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)328         public void writeToParcel(Parcel dest, int flags) {
329             dest.writeInt(mId);
330             dest.writeString(mName);
331             dest.writeIntArray(mAvailableTransports);
332             dest.writeBoolean(mProjecting);
333             dest.writeBundle(mExtras);
334         }
335 
336         /** Returns the device id which uniquely identifies the mobile device within projection  */
337         @AddedInOrBefore(majorVersion = 33)
getId()338         public int getId() {
339             return mId;
340         }
341 
342         /** Returns the name of the device */
343         @AddedInOrBefore(majorVersion = 33)
getName()344         public @NonNull String getName() {
345             return mName;
346         }
347 
348         /** Returns a list of available projection transports. See {@code PROJECTION_TRANSPORT_*}
349          * for possible values. */
350         @AddedInOrBefore(majorVersion = 33)
getAvailableTransports()351         public @NonNull List<Integer> getAvailableTransports() {
352             List<Integer> transports = new ArrayList<>(mAvailableTransports.length);
353             for (int transport : mAvailableTransports) {
354                 transports.add(transport);
355             }
356             return transports;
357         }
358 
359         /** Indicates whether this mobile device is currently projecting */
360         @AddedInOrBefore(majorVersion = 33)
isProjecting()361         public boolean isProjecting() {
362             return mProjecting;
363         }
364 
365         /** Returns extra information for mobile device */
366         @AddedInOrBefore(majorVersion = 33)
getExtras()367         public @NonNull Bundle getExtras() {
368             return mExtras == null ? new Bundle() : new Bundle(mExtras);
369         }
370 
371         /** Parcelable implementation */
372         @Override
373         @AddedInOrBefore(majorVersion = 33)
describeContents()374         public int describeContents() {
375             return 0;
376         }
377 
378         /**
379          * Creates new instance of {@link Builder}
380          *
381          * @param id uniquely identifies the device
382          * @param name name of the connected device
383          * @return the instance of {@link Builder}
384          */
385         @AddedInOrBefore(majorVersion = 33)
builder(int id, String name)386         public static @NonNull Builder builder(int id, String name) {
387             return new Builder(id, name);
388         }
389 
390         @Override
toString()391         public String toString() {
392             return "MobileDevice{"
393                     + "mId=" + mId
394                     + ", mName='" + mName + '\''
395                     + ", mAvailableTransports=" + Arrays.toString(mAvailableTransports)
396                     + ", mProjecting=" + mProjecting
397                     + (mExtras != null ? ", (has extras)" : "")
398                     + '}';
399         }
400 
401         /**
402          * Builder class for {@link MobileDevice}
403          */
404         public static final class Builder {
405             private int mId;
406             private String mName;
407             private IntArray mAvailableTransports = new IntArray();
408             private boolean mProjecting;
409             private Bundle mExtras;
410 
Builder(int id, String name)411             private Builder(int id, String name) {
412                 mId = id;
413                 if (name == null) {
414                     throw new IllegalArgumentException("Name of the device can't be null");
415                 }
416                 mName = name;
417             }
418 
419             /**
420              * Add supported transport
421              *
422              * @param transport supported transport by given device, must be one of the
423              * {@code PROJECTION_TRANSPORT_*}
424              * @return this builder
425              */
426             @AddedInOrBefore(majorVersion = 33)
addTransport(@rojectionTransport int transport)427             public @NonNull Builder addTransport(@ProjectionTransport int transport) {
428                 checkProjectionTransport(transport);
429                 mAvailableTransports.add(transport);
430                 return this;
431             }
432 
433             /**
434              * Indicate whether the mobile device currently projecting or not.
435              *
436              * @param projecting {@code True} if this mobile device currently projecting
437              * @return this builder
438              */
439             @AddedInOrBefore(majorVersion = 33)
setProjecting(boolean projecting)440             public @NonNull Builder setProjecting(boolean projecting) {
441                 mProjecting = projecting;
442                 return this;
443             }
444 
445             /**
446              * Add extra information for mobile device
447              *
448              * @param extras provides an arbitrary extra information about this mobile device
449              * @return this builder
450              */
451             @AddedInOrBefore(majorVersion = 33)
setExtras(Bundle extras)452             public @NonNull Builder setExtras(Bundle extras) {
453                 mExtras = extras;
454                 return this;
455             }
456 
457             /** Creates new instance of {@link MobileDevice} */
458             @AddedInOrBefore(majorVersion = 33)
build()459             public @NonNull MobileDevice build() {
460                 return new MobileDevice(this);
461             }
462         }
463     }
464 }
465