1 /*
2  * Copyright (C) 2010 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.mtp;
18 
19 import android.annotation.NonNull;
20 import android.os.Build;
21 
22 import com.android.internal.util.Preconditions;
23 
24 import dalvik.system.VMRuntime;
25 
26 /**
27  * This class encapsulates information about an object on an MTP device.
28  * This corresponds to the ObjectInfo Dataset described in
29  * section 5.3.1 of the MTP specification.
30  */
31 public final class MtpObjectInfo {
32     private int mHandle;
33     private int mStorageId;
34     private int mFormat;
35     private int mProtectionStatus;
36     private int mCompressedSize;
37     private int mThumbFormat;
38     private int mThumbCompressedSize;
39     private int mThumbPixWidth;
40     private int mThumbPixHeight;
41     private int mImagePixWidth;
42     private int mImagePixHeight;
43     private int mImagePixDepth;
44     private int mParent;
45     private int mAssociationType;
46     private int mAssociationDesc;
47     private int mSequenceNumber;
48     private String mName = "";
49     private long mDateCreated;
50     private long mDateModified;
51     private String mKeywords = "";
52 
53     // only instantiated via JNI or via a builder
MtpObjectInfo()54     private MtpObjectInfo() {
55     }
56 
57     /**
58      * Returns the object handle for the MTP object
59      *
60      * @return the object handle
61      */
getObjectHandle()62     public final int getObjectHandle() {
63         return mHandle;
64     }
65 
66     /**
67      * Returns the storage ID for the MTP object's storage unit
68      *
69      * @return the storage ID
70      */
getStorageId()71     public final int getStorageId() {
72         return mStorageId;
73     }
74 
75     /**
76      * Returns the format code for the MTP object
77      *
78      * @return the format code
79      */
getFormat()80     public final int getFormat() {
81         return mFormat;
82     }
83 
84     /**
85      * Returns the protection status for the MTP object
86      * Possible values are:
87      *
88      * <ul>
89      * <li> {@link android.mtp.MtpConstants#PROTECTION_STATUS_NONE}
90      * <li> {@link android.mtp.MtpConstants#PROTECTION_STATUS_READ_ONLY}
91      * <li> {@link android.mtp.MtpConstants#PROTECTION_STATUS_NON_TRANSFERABLE_DATA}
92      * </ul>
93      *
94      * @return the protection status
95      */
getProtectionStatus()96     public final int getProtectionStatus() {
97         return mProtectionStatus;
98     }
99 
100     /**
101      * Returns the size of the MTP object
102      *
103      * @return the object size
104      */
getCompressedSize()105     public final int getCompressedSize() {
106         Preconditions.checkState(mCompressedSize >= 0);
107         return mCompressedSize;
108     }
109 
110     /**
111      * Returns the size of the MTP object
112      *
113      * @return the object size
114      */
getCompressedSizeLong()115     public final long getCompressedSizeLong() {
116         return uint32ToLong(mCompressedSize);
117     }
118 
119     /**
120      * Returns the format code for the MTP object's thumbnail
121      * Will be zero for objects with no thumbnail
122      *
123      * @return the thumbnail format code
124      */
getThumbFormat()125     public final int getThumbFormat() {
126         return mThumbFormat;
127     }
128 
129     /**
130      * Returns the size of the MTP object's thumbnail
131      * Will be zero for objects with no thumbnail
132      *
133      * @return the thumbnail size
134      */
getThumbCompressedSize()135     public final int getThumbCompressedSize() {
136         Preconditions.checkState(mThumbCompressedSize >= 0);
137         return mThumbCompressedSize;
138     }
139 
140     /**
141      * Returns the size of the MTP object's thumbnail
142      * Will be zero for objects with no thumbnail
143      *
144      * @return the thumbnail size
145      */
getThumbCompressedSizeLong()146     public final long getThumbCompressedSizeLong() {
147         return uint32ToLong(mThumbCompressedSize);
148     }
149 
150     /**
151      * Returns the width of the MTP object's thumbnail in pixels
152      * Will be zero for objects with no thumbnail
153      *
154      * @return the thumbnail width
155      */
getThumbPixWidth()156     public final int getThumbPixWidth() {
157         Preconditions.checkState(mThumbPixWidth >= 0);
158         return mThumbPixWidth;
159     }
160 
161     /**
162      * Returns the width of the MTP object's thumbnail in pixels
163      * Will be zero for objects with no thumbnail
164      *
165      * @return the thumbnail width
166      */
getThumbPixWidthLong()167     public final long getThumbPixWidthLong() {
168         return uint32ToLong(mThumbPixWidth);
169     }
170 
171     /**
172      * Returns the height of the MTP object's thumbnail in pixels
173      * Will be zero for objects with no thumbnail
174      *
175      * @return the thumbnail height
176      */
getThumbPixHeight()177     public final int getThumbPixHeight() {
178         Preconditions.checkState(mThumbPixHeight >= 0);
179         return mThumbPixHeight;
180     }
181 
182     /**
183      * Returns the height of the MTP object's thumbnail in pixels
184      * Will be zero for objects with no thumbnail
185      *
186      * @return the thumbnail height
187      */
getThumbPixHeightLong()188     public final long getThumbPixHeightLong() {
189         return uint32ToLong(mThumbPixHeight);
190     }
191 
192     /**
193      * Returns the width of the MTP object in pixels
194      * Will be zero for non-image objects
195      *
196      * @return the image width
197      */
getImagePixWidth()198     public final int getImagePixWidth() {
199         Preconditions.checkState(mImagePixWidth >= 0);
200         return mImagePixWidth;
201     }
202 
203     /**
204      * Returns the width of the MTP object in pixels
205      * Will be zero for non-image objects
206      *
207      * @return the image width
208      */
getImagePixWidthLong()209     public final long getImagePixWidthLong() {
210         return uint32ToLong(mImagePixWidth);
211     }
212 
213     /**
214      * Returns the height of the MTP object in pixels
215      * Will be zero for non-image objects
216      *
217      * @return the image height
218      */
getImagePixHeight()219     public final int getImagePixHeight() {
220         Preconditions.checkState(mImagePixHeight >= 0);
221         return mImagePixHeight;
222     }
223 
224     /**
225      * Returns the height of the MTP object in pixels
226      * Will be zero for non-image objects
227      *
228      * @return the image height
229      */
getImagePixHeightLong()230     public final long getImagePixHeightLong() {
231         return uint32ToLong(mImagePixHeight);
232     }
233 
234     /**
235      * Returns the depth of the MTP object in bits per pixel
236      * Will be zero for non-image objects
237      *
238      * @return the image depth
239      */
getImagePixDepth()240     public final int getImagePixDepth() {
241         Preconditions.checkState(mImagePixDepth >= 0);
242         return mImagePixDepth;
243     }
244 
245     /**
246      * Returns the depth of the MTP object in bits per pixel
247      * Will be zero for non-image objects
248      *
249      * @return the image depth
250      */
getImagePixDepthLong()251     public final long getImagePixDepthLong() {
252         return uint32ToLong(mImagePixDepth);
253     }
254 
255     /**
256      * Returns the object handle for the object's parent
257      * Will be zero for the root directory of a storage unit
258      *
259      * @return the object's parent
260      */
getParent()261     public final int getParent() {
262         return mParent;
263     }
264 
265     /**
266      * Returns the association type for the MTP object
267      * Will be zero objects that are not of format
268      * {@link android.mtp.MtpConstants#FORMAT_ASSOCIATION}
269      * For directories the association type is typically
270      * {@link android.mtp.MtpConstants#ASSOCIATION_TYPE_GENERIC_FOLDER}
271      *
272      * @return the object's association type
273      */
getAssociationType()274     public final int getAssociationType() {
275         return mAssociationType;
276     }
277 
278     /**
279      * Returns the association description for the MTP object
280      * Will be zero objects that are not of format
281      * {@link android.mtp.MtpConstants#FORMAT_ASSOCIATION}
282      *
283      * @return the object's association description
284      */
getAssociationDesc()285     public final int getAssociationDesc() {
286         return mAssociationDesc;
287     }
288 
289     /**
290      * Returns the sequence number for the MTP object
291      * This field is typically not used for MTP devices,
292      * but is sometimes used to define a sequence of photos
293      * on PTP cameras.
294      *
295      * @return the object's sequence number
296      */
getSequenceNumber()297     public final int getSequenceNumber() {
298         Preconditions.checkState(mSequenceNumber >= 0);
299         return mSequenceNumber;
300     }
301 
302     /**
303      * Returns the sequence number for the MTP object
304      * This field is typically not used for MTP devices,
305      * but is sometimes used to define a sequence of photos
306      * on PTP cameras.
307      *
308      * @return the object's sequence number
309      */
getSequenceNumberLong()310     public final long getSequenceNumberLong() {
311         return uint32ToLong(mSequenceNumber);
312     }
313 
314    /**
315      * Returns the name of the MTP object
316      *
317      * @return the object's name
318      */
getName()319     public final @NonNull String getName() {
320         return mName;
321     }
322 
323    /**
324      * Returns the creation date of the MTP object
325      * The value is represented as milliseconds since January 1, 1970
326      *
327      * @return the object's creation date
328      */
getDateCreated()329     public final long getDateCreated() {
330         return mDateCreated;
331     }
332 
333    /**
334      * Returns the modification date of the MTP object
335      * The value is represented as milliseconds since January 1, 1970
336      *
337      * @return the object's modification date
338      */
getDateModified()339     public final long getDateModified() {
340         return mDateModified;
341     }
342 
343    /**
344      * Returns a comma separated list of keywords for the MTP object
345      *
346      * @return the object's keyword list
347      */
getKeywords()348     public final @NonNull String getKeywords() {
349         return mKeywords;
350     }
351 
352     /**
353      * Builds a new object info instance.
354      */
355     public static class Builder {
356         private MtpObjectInfo mObjectInfo;
357 
Builder()358         public Builder() {
359             mObjectInfo = new MtpObjectInfo();
360             mObjectInfo.mHandle = -1;
361         }
362 
363         /**
364          * Creates a builder on a copy of an existing object info.
365          * All fields, except the object handle will be copied.
366          *
367          * @param objectInfo object info of an existing entry
368          */
Builder(MtpObjectInfo objectInfo)369         public Builder(MtpObjectInfo objectInfo) {
370             mObjectInfo = new MtpObjectInfo();
371             mObjectInfo.mHandle = -1;
372             mObjectInfo.mAssociationDesc = objectInfo.mAssociationDesc;
373             mObjectInfo.mAssociationType = objectInfo.mAssociationType;
374             mObjectInfo.mCompressedSize = objectInfo.mCompressedSize;
375             mObjectInfo.mDateCreated = objectInfo.mDateCreated;
376             mObjectInfo.mDateModified = objectInfo.mDateModified;
377             mObjectInfo.mFormat = objectInfo.mFormat;
378             mObjectInfo.mImagePixDepth = objectInfo.mImagePixDepth;
379             mObjectInfo.mImagePixHeight = objectInfo.mImagePixHeight;
380             mObjectInfo.mImagePixWidth = objectInfo.mImagePixWidth;
381             mObjectInfo.mKeywords = objectInfo.mKeywords;
382             mObjectInfo.mName = objectInfo.mName;
383             mObjectInfo.mParent = objectInfo.mParent;
384             mObjectInfo.mProtectionStatus = objectInfo.mProtectionStatus;
385             mObjectInfo.mSequenceNumber = objectInfo.mSequenceNumber;
386             mObjectInfo.mStorageId = objectInfo.mStorageId;
387             mObjectInfo.mThumbCompressedSize = objectInfo.mThumbCompressedSize;
388             mObjectInfo.mThumbFormat = objectInfo.mThumbFormat;
389             mObjectInfo.mThumbPixHeight = objectInfo.mThumbPixHeight;
390             mObjectInfo.mThumbPixWidth = objectInfo.mThumbPixWidth;
391         }
392 
setObjectHandle(int value)393         public Builder setObjectHandle(int value) {
394             mObjectInfo.mHandle = value;
395             return this;
396         }
397 
setAssociationDesc(int value)398         public Builder setAssociationDesc(int value) {
399             mObjectInfo.mAssociationDesc = value;
400             return this;
401         }
402 
setAssociationType(int value)403         public Builder setAssociationType(int value) {
404             mObjectInfo.mAssociationType = value;
405             return this;
406         }
407 
setCompressedSize(long value)408         public Builder setCompressedSize(long value) {
409             mObjectInfo.mCompressedSize = longToUint32(value, "value");
410             return this;
411         }
412 
setDateCreated(long value)413         public Builder setDateCreated(long value) {
414             mObjectInfo.mDateCreated = value;
415             return this;
416         }
417 
setDateModified(long value)418         public Builder setDateModified(long value) {
419             mObjectInfo.mDateModified = value;
420             return this;
421         }
422 
setFormat(int value)423         public Builder setFormat(int value) {
424             mObjectInfo.mFormat = value;
425             return this;
426         }
427 
setImagePixDepth(long value)428         public Builder setImagePixDepth(long value) {
429             mObjectInfo.mImagePixDepth = longToUint32(value, "value");
430             return this;
431         }
432 
setImagePixHeight(long value)433         public Builder setImagePixHeight(long value) {
434             mObjectInfo.mImagePixHeight = longToUint32(value, "value");
435             return this;
436         }
437 
setImagePixWidth(long value)438         public Builder setImagePixWidth(long value) {
439             mObjectInfo.mImagePixWidth = longToUint32(value, "value");
440             return this;
441         }
442 
setKeywords(@onNull String value)443         public Builder setKeywords(@NonNull String value) {
444             if (VMRuntime.getRuntime().getTargetSdkVersion() > Build.VERSION_CODES.N_MR1) {
445                 Preconditions.checkNotNull(value);
446             } else if (value == null) {
447                 // Before N_MR1 we accept null value and it was regarded as an empty string in
448                 // MtpDevice#sendObjectInfo.
449                 value = "";
450             }
451             mObjectInfo.mKeywords = value;
452             return this;
453         }
454 
setName(@onNull String value)455         public Builder setName(@NonNull String value) {
456             Preconditions.checkNotNull(value);
457             mObjectInfo.mName = value;
458             return this;
459         }
460 
setParent(int value)461         public Builder setParent(int value) {
462             mObjectInfo.mParent = value;
463             return this;
464         }
465 
setProtectionStatus(int value)466         public Builder setProtectionStatus(int value) {
467             mObjectInfo.mProtectionStatus = value;
468             return this;
469         }
470 
setSequenceNumber(long value)471         public Builder setSequenceNumber(long value) {
472             mObjectInfo.mSequenceNumber = longToUint32(value, "value");
473             return this;
474         }
475 
setStorageId(int value)476         public Builder setStorageId(int value) {
477             mObjectInfo.mStorageId = value;
478             return this;
479         }
480 
setThumbCompressedSize(long value)481         public Builder setThumbCompressedSize(long value) {
482             mObjectInfo.mThumbCompressedSize = longToUint32(value, "value");
483             return this;
484         }
485 
setThumbFormat(int value)486         public Builder setThumbFormat(int value) {
487             mObjectInfo.mThumbFormat = value;
488             return this;
489         }
490 
setThumbPixHeight(long value)491         public Builder setThumbPixHeight(long value) {
492             mObjectInfo.mThumbPixHeight = longToUint32(value, "value");
493             return this;
494         }
495 
setThumbPixWidth(long value)496         public Builder setThumbPixWidth(long value) {
497             mObjectInfo.mThumbPixWidth = longToUint32(value, "value");
498             return this;
499         }
500 
501         /**
502          * Builds the object info instance. Once called, methods of the builder
503          * must not be called anymore.
504          *
505          * @return the object info of the newly created file, or NULL in case
506          *         of an error.
507          */
build()508         public MtpObjectInfo build() {
509             MtpObjectInfo result = mObjectInfo;
510             mObjectInfo = null;
511             return result;
512         }
513     }
514 
uint32ToLong(int value)515     private static long uint32ToLong(int value) {
516         return value < 0 ? 0x100000000L + value : value;
517     }
518 
longToUint32(long value, String valueName)519     private static int longToUint32(long value, String valueName) {
520         Preconditions.checkArgumentInRange(value, 0, 0xffffffffL, valueName);
521         return (int) value;
522     }
523 }
524