• 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
278     @AddedInOrBefore(majorVersion = 33)
toString()279     public String toString() {
280         return "ProjectionStatus{"
281                 + "mPackageName='" + mPackageName + '\''
282                 + ", mState=" + mState
283                 + ", mTransport=" + mTransport
284                 + ", mConnectedMobileDevices=" + mConnectedMobileDevices
285                 + (mExtras != null ? " (has extras)" : "")
286                 + '}';
287     }
288 
289     /** Class that represents information about connected mobile device. */
290     public static final class MobileDevice implements Parcelable {
291         private final int mId;
292         private final String mName;
293         private final int[] mAvailableTransports;
294         private final boolean mProjecting;
295         private final Bundle mExtras;
296 
297         /** Creator for this class. Required to have in parcelable implementations. */
298         @AddedInOrBefore(majorVersion = 33)
299         public static final Creator<MobileDevice> CREATOR = new Creator<MobileDevice>() {
300             @Override
301             public MobileDevice createFromParcel(Parcel source) {
302                 return new MobileDevice(source);
303             }
304 
305             @Override
306             public MobileDevice[] newArray(int size) {
307                 return new MobileDevice[size];
308             }
309         };
310 
MobileDevice(Builder builder)311         private MobileDevice(Builder builder) {
312             mId = builder.mId;
313             mName = builder.mName;
314             mAvailableTransports = builder.mAvailableTransports.toArray();
315             mProjecting = builder.mProjecting;
316             mExtras = builder.mExtras == null ? null : new Bundle(builder.mExtras);
317         }
318 
MobileDevice(Parcel source)319         private MobileDevice(Parcel source) {
320             mId = source.readInt();
321             mName = source.readString();
322             mAvailableTransports = source.createIntArray();
323             mProjecting = source.readBoolean();
324             mExtras = source.readBundle(getClass().getClassLoader());
325         }
326 
327         @Override
328         @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)329         public void writeToParcel(Parcel dest, int flags) {
330             dest.writeInt(mId);
331             dest.writeString(mName);
332             dest.writeIntArray(mAvailableTransports);
333             dest.writeBoolean(mProjecting);
334             dest.writeBundle(mExtras);
335         }
336 
337         /** Returns the device id which uniquely identifies the mobile device within projection  */
338         @AddedInOrBefore(majorVersion = 33)
getId()339         public int getId() {
340             return mId;
341         }
342 
343         /** Returns the name of the device */
344         @AddedInOrBefore(majorVersion = 33)
getName()345         public @NonNull String getName() {
346             return mName;
347         }
348 
349         /** Returns a list of available projection transports. See {@code PROJECTION_TRANSPORT_*}
350          * for possible values. */
351         @AddedInOrBefore(majorVersion = 33)
getAvailableTransports()352         public @NonNull List<Integer> getAvailableTransports() {
353             List<Integer> transports = new ArrayList<>(mAvailableTransports.length);
354             for (int transport : mAvailableTransports) {
355                 transports.add(transport);
356             }
357             return transports;
358         }
359 
360         /** Indicates whether this mobile device is currently projecting */
361         @AddedInOrBefore(majorVersion = 33)
isProjecting()362         public boolean isProjecting() {
363             return mProjecting;
364         }
365 
366         /** Returns extra information for mobile device */
367         @AddedInOrBefore(majorVersion = 33)
getExtras()368         public @NonNull Bundle getExtras() {
369             return mExtras == null ? new Bundle() : new Bundle(mExtras);
370         }
371 
372         /** Parcelable implementation */
373         @Override
374         @AddedInOrBefore(majorVersion = 33)
describeContents()375         public int describeContents() {
376             return 0;
377         }
378 
379         /**
380          * Creates new instance of {@link Builder}
381          *
382          * @param id uniquely identifies the device
383          * @param name name of the connected device
384          * @return the instance of {@link Builder}
385          */
386         @AddedInOrBefore(majorVersion = 33)
builder(int id, String name)387         public static @NonNull Builder builder(int id, String name) {
388             return new Builder(id, name);
389         }
390 
391         @Override
392         @AddedInOrBefore(majorVersion = 33)
toString()393         public String toString() {
394             return "MobileDevice{"
395                     + "mId=" + mId
396                     + ", mName='" + mName + '\''
397                     + ", mAvailableTransports=" + Arrays.toString(mAvailableTransports)
398                     + ", mProjecting=" + mProjecting
399                     + (mExtras != null ? ", (has extras)" : "")
400                     + '}';
401         }
402 
403         /**
404          * Builder class for {@link MobileDevice}
405          */
406         public static final class Builder {
407             private int mId;
408             private String mName;
409             private IntArray mAvailableTransports = new IntArray();
410             private boolean mProjecting;
411             private Bundle mExtras;
412 
Builder(int id, String name)413             private Builder(int id, String name) {
414                 mId = id;
415                 if (name == null) {
416                     throw new IllegalArgumentException("Name of the device can't be null");
417                 }
418                 mName = name;
419             }
420 
421             /**
422              * Add supported transport
423              *
424              * @param transport supported transport by given device, must be one of the
425              * {@code PROJECTION_TRANSPORT_*}
426              * @return this builder
427              */
428             @AddedInOrBefore(majorVersion = 33)
addTransport(@rojectionTransport int transport)429             public @NonNull Builder addTransport(@ProjectionTransport int transport) {
430                 checkProjectionTransport(transport);
431                 mAvailableTransports.add(transport);
432                 return this;
433             }
434 
435             /**
436              * Indicate whether the mobile device currently projecting or not.
437              *
438              * @param projecting {@code True} if this mobile device currently projecting
439              * @return this builder
440              */
441             @AddedInOrBefore(majorVersion = 33)
setProjecting(boolean projecting)442             public @NonNull Builder setProjecting(boolean projecting) {
443                 mProjecting = projecting;
444                 return this;
445             }
446 
447             /**
448              * Add extra information for mobile device
449              *
450              * @param extras provides an arbitrary extra information about this mobile device
451              * @return this builder
452              */
453             @AddedInOrBefore(majorVersion = 33)
setExtras(Bundle extras)454             public @NonNull Builder setExtras(Bundle extras) {
455                 mExtras = extras;
456                 return this;
457             }
458 
459             /** Creates new instance of {@link MobileDevice} */
460             @AddedInOrBefore(majorVersion = 33)
build()461             public @NonNull MobileDevice build() {
462                 return new MobileDevice(this);
463             }
464         }
465     }
466 }
467