1 /*
2  * Copyright 2017 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.os.Parcel;
22 import android.os.Parcelable;
23 
24 import libcore.util.HexEncoding;
25 
26 import java.util.Arrays;
27 
28 /**
29  * A class describing messages send to or from nanoapps through the Context Hub Service.
30  *
31  * The basis of the class is in the IContextHub.hal ContextHubMsg definition.
32  *
33  * @hide
34  */
35 @SystemApi
36 public final class NanoAppMessage implements Parcelable {
37     private static final int DEBUG_LOG_NUM_BYTES = 16;
38     private long mNanoAppId;
39     private int mMessageType;
40     private byte[] mMessageBody;
41     private boolean mIsBroadcasted;
42 
NanoAppMessage( long nanoAppId, int messageType, byte[] messageBody, boolean broadcasted)43     private NanoAppMessage(
44             long nanoAppId, int messageType, byte[] messageBody, boolean broadcasted) {
45         mNanoAppId = nanoAppId;
46         mMessageType = messageType;
47         mMessageBody = messageBody;
48         mIsBroadcasted = broadcasted;
49     }
50 
51     /**
52      * Creates a NanoAppMessage object to send to a nanoapp.
53      *
54      * This factory method can be used to generate a NanoAppMessage object to be used in
55      * the ContextHubClient.sendMessageToNanoApp API.
56      *
57      * @param targetNanoAppId the ID of the nanoapp to send the message to
58      * @param messageType the nanoapp-dependent message type
59      * @param messageBody the byte array message contents
60      *
61      * @return the NanoAppMessage object
62      */
createMessageToNanoApp( long targetNanoAppId, int messageType, byte[] messageBody)63     public static NanoAppMessage createMessageToNanoApp(
64             long targetNanoAppId, int messageType, byte[] messageBody) {
65         return new NanoAppMessage(
66                 targetNanoAppId, messageType, messageBody, false /* broadcasted */);
67     }
68 
69     /**
70      * Creates a NanoAppMessage object sent from a nanoapp.
71      *
72      * This factory method is intended only to be used by the Context Hub Service when delivering
73      * messages from a nanoapp to clients.
74      *
75      * @param sourceNanoAppId the ID of the nanoapp that the message was sent from
76      * @param messageType the nanoapp-dependent message type
77      * @param messageBody the byte array message contents
78      * @param broadcasted {@code true} if the message was broadcasted, {@code false} otherwise
79      *
80      * @return the NanoAppMessage object
81      */
createMessageFromNanoApp( long sourceNanoAppId, int messageType, byte[] messageBody, boolean broadcasted)82     public static NanoAppMessage createMessageFromNanoApp(
83             long sourceNanoAppId, int messageType, byte[] messageBody, boolean broadcasted) {
84         return new NanoAppMessage(sourceNanoAppId, messageType, messageBody, broadcasted);
85     }
86 
87     /**
88      * @return the ID of the source or destination nanoapp
89      */
getNanoAppId()90     public long getNanoAppId() {
91         return mNanoAppId;
92     }
93 
94     /**
95      * @return the type of the message that is nanoapp-dependent
96      */
getMessageType()97     public int getMessageType() {
98         return mMessageType;
99     }
100 
101     /**
102      * @return the byte array contents of the message
103      */
getMessageBody()104     public byte[] getMessageBody() {
105         return mMessageBody;
106     }
107 
108     /**
109      * @return {@code true} if the message is broadcasted, {@code false} otherwise
110      */
isBroadcastMessage()111     public boolean isBroadcastMessage() {
112         return mIsBroadcasted;
113     }
114 
NanoAppMessage(Parcel in)115     private NanoAppMessage(Parcel in) {
116         mNanoAppId = in.readLong();
117         mIsBroadcasted = (in.readInt() == 1);
118         mMessageType = in.readInt();
119 
120         int msgSize = in.readInt();
121         mMessageBody = new byte[msgSize];
122         in.readByteArray(mMessageBody);
123     }
124 
125     @Override
describeContents()126     public int describeContents() {
127         return 0;
128     }
129 
130     @Override
writeToParcel(Parcel out, int flags)131     public void writeToParcel(Parcel out, int flags) {
132         out.writeLong(mNanoAppId);
133         out.writeInt(mIsBroadcasted ? 1 : 0);
134         out.writeInt(mMessageType);
135 
136         out.writeInt(mMessageBody.length);
137         out.writeByteArray(mMessageBody);
138     }
139 
140     public static final @NonNull Creator<NanoAppMessage> CREATOR =
141             new Creator<NanoAppMessage>() {
142                 @Override
143                 public NanoAppMessage createFromParcel(Parcel in) {
144                     return new NanoAppMessage(in);
145                 }
146 
147                 @Override
148                 public NanoAppMessage[] newArray(int size) {
149                     return new NanoAppMessage[size];
150                 }
151             };
152 
153     @NonNull
154     @Override
toString()155     public String toString() {
156         int length = mMessageBody.length;
157 
158         String ret = "NanoAppMessage[type = " + mMessageType + ", length = " + mMessageBody.length
159                 + " bytes, " + (mIsBroadcasted ? "broadcast" : "unicast") + ", nanoapp = 0x"
160                 + Long.toHexString(mNanoAppId) + "](";
161         if (length > 0) {
162             ret += "data = 0x";
163         }
164         for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) {
165             ret += HexEncoding.encodeToString(mMessageBody[i], true /* upperCase */);
166 
167             if ((i + 1) % 4 == 0) {
168                 ret += " ";
169             }
170         }
171         if (length > DEBUG_LOG_NUM_BYTES) {
172             ret += "...";
173         }
174         ret += ")";
175 
176         return ret;
177     }
178 
179     @Override
equals(@ullable Object object)180     public boolean equals(@Nullable Object object) {
181         if (object == this) {
182             return true;
183         }
184 
185         boolean isEqual = false;
186         if (object instanceof NanoAppMessage) {
187             NanoAppMessage other = (NanoAppMessage) object;
188             isEqual = (other.getNanoAppId() == mNanoAppId)
189                     && (other.getMessageType() == mMessageType)
190                     && (other.isBroadcastMessage() == mIsBroadcasted)
191                     && Arrays.equals(other.getMessageBody(), mMessageBody);
192         }
193 
194         return isEqual;
195     }
196 }
197