1 /*
2  * Copyright 2021 Google LLC
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  *   https://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 package com.google.android.enterprise.connectedapps.parcelablewrappers;
17 
18 import android.os.Parcel;
19 import android.os.Parcelable;
20 import com.google.android.enterprise.connectedapps.internal.Bundler;
21 import com.google.android.enterprise.connectedapps.internal.BundlerType;
22 import com.google.common.base.Optional;
23 
24 /**
25  * Wrapper for reading & writing {@link Optional} instances from and to {@link Parcel} instances.
26  */
27 public class ParcelableGuavaOptional<E> implements Parcelable {
28 
29   private static final int NULL = -1;
30   private static final int ABSENT = 0;
31   private static final int PRESENT = 1;
32 
33   private final Bundler bundler;
34   private final BundlerType type;
35   private final Optional<E> optional;
36 
37   /**
38    * Create a wrapper for a given optional.
39    *
40    * <p>The passed in {@link Bundler} must be capable of bundling {@code F}.
41    */
of( Bundler bundler, BundlerType type, Optional<F> optional)42   public static <F> ParcelableGuavaOptional<F> of(
43       Bundler bundler, BundlerType type, Optional<F> optional) {
44     return new ParcelableGuavaOptional<>(bundler, type, optional);
45   }
46 
get()47   public Optional<E> get() {
48     return optional;
49   }
50 
ParcelableGuavaOptional(Bundler bundler, BundlerType type, Optional<E> optional)51   private ParcelableGuavaOptional(Bundler bundler, BundlerType type, Optional<E> optional) {
52     if (bundler == null || type == null) {
53       throw new NullPointerException();
54     }
55     this.bundler = bundler;
56     this.type = type;
57     this.optional = optional;
58   }
59 
ParcelableGuavaOptional(Parcel in)60   private ParcelableGuavaOptional(Parcel in) {
61     bundler = in.readParcelable(Bundler.class.getClassLoader());
62 
63     int presentValue = in.readInt();
64 
65     if (presentValue == NULL) {
66       type = null;
67       optional = null;
68       return;
69     }
70 
71     boolean isPresent = presentValue == PRESENT;
72     type = (BundlerType) in.readParcelable(Bundler.class.getClassLoader());
73     if (isPresent) {
74       BundlerType valueType = type.typeArguments().get(0);
75 
76       @SuppressWarnings("unchecked")
77       E value = (E) bundler.readFromParcel(in, valueType);
78 
79       optional = Optional.of(value);
80     } else {
81       optional = Optional.absent();
82     }
83   }
84 
85   @Override
writeToParcel(Parcel dest, int flags)86   public void writeToParcel(Parcel dest, int flags) {
87     dest.writeParcelable(bundler, flags);
88 
89     if (optional == null) {
90       dest.writeInt(NULL);
91       return;
92     }
93 
94     dest.writeInt(optional.isPresent() ? PRESENT : ABSENT);
95     dest.writeParcelable(type, flags);
96     if (optional.isPresent()) {
97       BundlerType valueType = type.typeArguments().get(0);
98       bundler.writeToParcel(dest, optional.get(), valueType, flags);
99     }
100   }
101 
102   @Override
describeContents()103   public int describeContents() {
104     return 0;
105   }
106 
107   @SuppressWarnings("rawtypes")
108   public static final Creator<ParcelableGuavaOptional> CREATOR =
109       new Creator<ParcelableGuavaOptional>() {
110         @Override
111         public ParcelableGuavaOptional createFromParcel(Parcel in) {
112           return new ParcelableGuavaOptional(in);
113         }
114 
115         @Override
116         public ParcelableGuavaOptional[] newArray(int size) {
117           return new ParcelableGuavaOptional[size];
118         }
119       };
120 }
121