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 package android.hardware.location; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 import android.app.PendingIntent; 22 import android.content.Intent; 23 24 import java.util.Objects; 25 26 /** 27 * A helper class to retrieve information about a Intent event received for a PendingIntent 28 * registered with {@link ContextHubManager.createClient(ContextHubInfo, PendingIntent, long)}. 29 * This object can only be created through the factory method 30 * {@link ContextHubIntentEvent.fromIntent(Intent)}. 31 * 32 * @hide 33 */ 34 @SystemApi 35 public class ContextHubIntentEvent { 36 @ContextHubManager.Event private final int mEventType; 37 38 @NonNull private final ContextHubInfo mContextHubInfo; 39 40 private final long mNanoAppId; 41 42 private final NanoAppMessage mNanoAppMessage; 43 44 private final int mNanoAppAbortCode; 45 46 private final int mClientAuthorizationState; 47 ContextHubIntentEvent( @onNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, long nanoAppId, NanoAppMessage nanoAppMessage, int nanoAppAbortCode, @ContextHubManager.AuthorizationState int clientAuthorizationState)48 private ContextHubIntentEvent( 49 @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, 50 long nanoAppId, NanoAppMessage nanoAppMessage, int nanoAppAbortCode, 51 @ContextHubManager.AuthorizationState int clientAuthorizationState) { 52 mContextHubInfo = contextHubInfo; 53 mEventType = eventType; 54 mNanoAppId = nanoAppId; 55 mNanoAppMessage = nanoAppMessage; 56 mNanoAppAbortCode = nanoAppAbortCode; 57 mClientAuthorizationState = clientAuthorizationState; 58 } 59 ContextHubIntentEvent( @onNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType)60 private ContextHubIntentEvent( 61 @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType) { 62 this(contextHubInfo, eventType, -1 /* nanoAppId */, null /* nanoAppMessage */, 63 -1 /* nanoAppAbortCode */, 0 /* clientAuthorizationState */); 64 } 65 ContextHubIntentEvent( @onNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, long nanoAppId)66 private ContextHubIntentEvent( 67 @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, 68 long nanoAppId) { 69 this(contextHubInfo, eventType, nanoAppId, null /* nanoAppMessage */, 70 -1 /* nanoAppAbortCode */, 0 /* clientAuthorizationState */); 71 } 72 ContextHubIntentEvent( @onNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, long nanoAppId, @NonNull NanoAppMessage nanoAppMessage)73 private ContextHubIntentEvent( 74 @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, 75 long nanoAppId, @NonNull NanoAppMessage nanoAppMessage) { 76 this(contextHubInfo, eventType, nanoAppId, nanoAppMessage, -1 /* nanoAppAbortCode */, 77 0 /* clientAuthorizationState */); 78 } 79 ContextHubIntentEvent( @onNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, long nanoAppId, int nanoAppAbortCode)80 private ContextHubIntentEvent( 81 @NonNull ContextHubInfo contextHubInfo, @ContextHubManager.Event int eventType, 82 long nanoAppId, int nanoAppAbortCode) { 83 this(contextHubInfo, eventType, nanoAppId, null /* nanoAppMessage */, nanoAppAbortCode, 84 0 /* clientAuthorizationState */); 85 } 86 87 /** 88 * Creates a ContextHubIntentEvent object from an Intent received through a PendingIntent 89 * registered with {@link ContextHubManager.createClient(ContextHubInfo, PendingIntent, long)}. 90 * 91 * @param intent the Intent object from an Intent event 92 * @return the ContextHubIntentEvent object describing the event 93 * 94 * @throws IllegalArgumentException if the Intent was not a valid intent 95 */ 96 @NonNull fromIntent(@onNull Intent intent)97 public static ContextHubIntentEvent fromIntent(@NonNull Intent intent) { 98 Objects.requireNonNull(intent, "Intent cannot be null"); 99 100 hasExtraOrThrow(intent, ContextHubManager.EXTRA_CONTEXT_HUB_INFO); 101 ContextHubInfo info = intent.getParcelableExtra(ContextHubManager.EXTRA_CONTEXT_HUB_INFO, android.hardware.location.ContextHubInfo.class); 102 if (info == null) { 103 throw new IllegalArgumentException("ContextHubInfo extra was null"); 104 } 105 106 int eventType = getIntExtraOrThrow(intent, ContextHubManager.EXTRA_EVENT_TYPE); 107 ContextHubIntentEvent event; 108 switch (eventType) { 109 case ContextHubManager.EVENT_NANOAPP_LOADED: 110 case ContextHubManager.EVENT_NANOAPP_UNLOADED: 111 case ContextHubManager.EVENT_NANOAPP_ENABLED: 112 case ContextHubManager.EVENT_NANOAPP_DISABLED: 113 case ContextHubManager.EVENT_NANOAPP_ABORTED: 114 case ContextHubManager.EVENT_NANOAPP_MESSAGE: 115 case ContextHubManager.EVENT_CLIENT_AUTHORIZATION: // fall through 116 long nanoAppId = getLongExtraOrThrow(intent, ContextHubManager.EXTRA_NANOAPP_ID); 117 if (eventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) { 118 hasExtraOrThrow(intent, ContextHubManager.EXTRA_MESSAGE); 119 NanoAppMessage message = 120 intent.getParcelableExtra(ContextHubManager.EXTRA_MESSAGE, android.hardware.location.NanoAppMessage.class); 121 if (message == null) { 122 throw new IllegalArgumentException("NanoAppMessage extra was null"); 123 } 124 125 event = new ContextHubIntentEvent(info, eventType, nanoAppId, message); 126 } else if (eventType == ContextHubManager.EVENT_NANOAPP_ABORTED) { 127 int nanoAppAbortCode = getIntExtraOrThrow( 128 intent, ContextHubManager.EXTRA_NANOAPP_ABORT_CODE); 129 event = new ContextHubIntentEvent(info, eventType, nanoAppId, nanoAppAbortCode); 130 } else if (eventType == ContextHubManager.EVENT_CLIENT_AUTHORIZATION) { 131 int authState = getIntExtraOrThrow( 132 intent, ContextHubManager.EXTRA_CLIENT_AUTHORIZATION_STATE); 133 event = new ContextHubIntentEvent(info, eventType, nanoAppId, 134 null /* nanoAppMessage */, -1 /* nanoAppAbortCode */, authState); 135 } else { 136 event = new ContextHubIntentEvent(info, eventType, nanoAppId); 137 } 138 break; 139 140 case ContextHubManager.EVENT_HUB_RESET: 141 event = new ContextHubIntentEvent(info, eventType); 142 break; 143 144 default: 145 throw new IllegalArgumentException("Unknown intent event type " + eventType); 146 } 147 148 return event; 149 } 150 151 /** 152 * @return the event type of this Intent event 153 */ 154 @ContextHubManager.Event getEventType()155 public int getEventType() { 156 return mEventType; 157 } 158 159 /** 160 * @return the ContextHubInfo object describing the Context Hub this event was for 161 */ 162 @NonNull getContextHubInfo()163 public ContextHubInfo getContextHubInfo() { 164 return mContextHubInfo; 165 } 166 167 /** 168 * @return the ID of the nanoapp this event was for 169 * 170 * @throws UnsupportedOperationException if the event did not have a nanoapp associated 171 */ getNanoAppId()172 public long getNanoAppId() { 173 if (mEventType == ContextHubManager.EVENT_HUB_RESET) { 174 throw new UnsupportedOperationException( 175 "Cannot invoke getNanoAppId() on Context Hub reset event"); 176 } 177 return mNanoAppId; 178 } 179 180 /** 181 * @return the nanoapp's abort code 182 * 183 * @throws UnsupportedOperationException if this was not a nanoapp abort event 184 */ getNanoAppAbortCode()185 public int getNanoAppAbortCode() { 186 if (mEventType != ContextHubManager.EVENT_NANOAPP_ABORTED) { 187 throw new UnsupportedOperationException( 188 "Cannot invoke getNanoAppAbortCode() on non-abort event: " + mEventType); 189 } 190 return mNanoAppAbortCode; 191 } 192 193 /** 194 * @return the message from a nanoapp 195 * 196 * @throws UnsupportedOperationException if this was not a nanoapp message event 197 */ 198 @NonNull getNanoAppMessage()199 public NanoAppMessage getNanoAppMessage() { 200 if (mEventType != ContextHubManager.EVENT_NANOAPP_MESSAGE) { 201 throw new UnsupportedOperationException( 202 "Cannot invoke getNanoAppMessage() on non-message event: " + mEventType); 203 } 204 return mNanoAppMessage; 205 } 206 207 /** 208 * @return the client authorization state 209 * 210 * @throws UnsupportedOperationException if this was not a client authorization state event 211 */ 212 @ContextHubManager.AuthorizationState getClientAuthorizationState()213 public int getClientAuthorizationState() { 214 if (mEventType != ContextHubManager.EVENT_CLIENT_AUTHORIZATION) { 215 throw new UnsupportedOperationException( 216 "Cannot invoke getClientAuthorizationState() on non-authorization event: " 217 + mEventType); 218 } 219 return mClientAuthorizationState; 220 } 221 222 @NonNull 223 @Override toString()224 public String toString() { 225 String out = "ContextHubIntentEvent[eventType = " + mEventType 226 + ", contextHubId = " + mContextHubInfo.getId(); 227 228 if (mEventType != ContextHubManager.EVENT_HUB_RESET) { 229 out += ", nanoAppId = 0x" + Long.toHexString(mNanoAppId); 230 } 231 if (mEventType == ContextHubManager.EVENT_NANOAPP_ABORTED) { 232 out += ", nanoAppAbortCode = " + mNanoAppAbortCode; 233 } 234 if (mEventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) { 235 out += ", nanoAppMessage = " + mNanoAppMessage; 236 } 237 if (mEventType == ContextHubManager.EVENT_CLIENT_AUTHORIZATION) { 238 out += ", clientAuthState = " + mClientAuthorizationState; 239 } 240 241 return out + "]"; 242 } 243 244 @Override equals(@ullable Object object)245 public boolean equals(@Nullable Object object) { 246 if (object == this) { 247 return true; 248 } 249 250 boolean isEqual = false; 251 if (object instanceof ContextHubIntentEvent) { 252 ContextHubIntentEvent other = (ContextHubIntentEvent) object; 253 if (other.getEventType() == mEventType 254 && other.getContextHubInfo().equals(mContextHubInfo)) { 255 isEqual = true; 256 try { 257 if (mEventType != ContextHubManager.EVENT_HUB_RESET) { 258 isEqual &= (other.getNanoAppId() == mNanoAppId); 259 } 260 if (mEventType == ContextHubManager.EVENT_NANOAPP_ABORTED) { 261 isEqual &= (other.getNanoAppAbortCode() == mNanoAppAbortCode); 262 } 263 if (mEventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) { 264 isEqual &= other.getNanoAppMessage().equals(mNanoAppMessage); 265 } 266 if (mEventType == ContextHubManager.EVENT_CLIENT_AUTHORIZATION) { 267 isEqual &= other.getClientAuthorizationState() == mClientAuthorizationState; 268 } 269 } catch (UnsupportedOperationException e) { 270 isEqual = false; 271 } 272 } 273 } 274 275 return isEqual; 276 } 277 hasExtraOrThrow(Intent intent, String extra)278 private static void hasExtraOrThrow(Intent intent, String extra) { 279 if (!intent.hasExtra(extra)) { 280 throw new IllegalArgumentException("Intent did not have extra: " + extra); 281 } 282 } 283 getIntExtraOrThrow(Intent intent, String extra)284 private static int getIntExtraOrThrow(Intent intent, String extra) { 285 hasExtraOrThrow(intent, extra); 286 return intent.getIntExtra(extra, -1 /* defaultValue */); 287 } 288 getLongExtraOrThrow(Intent intent, String extra)289 private static long getLongExtraOrThrow(Intent intent, String extra) { 290 hasExtraOrThrow(intent, extra); 291 return intent.getLongExtra(extra, -1 /* defaultValue */); 292 } 293 } 294