| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.mtp; |
| |
| import android.content.ContentProviderClient; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.RemoteException; |
| import android.provider.MediaStore.Audio; |
| import android.provider.MediaStore.Files; |
| import android.provider.MediaStore.Images; |
| import android.util.Log; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * MtpPropertyGroup represents a list of MTP properties. |
| * {@hide} |
| */ |
| class MtpPropertyGroup { |
| private static final String TAG = MtpPropertyGroup.class.getSimpleName(); |
| |
| private class Property { |
| int code; |
| int type; |
| int column; |
| |
| Property(int code, int type, int column) { |
| this.code = code; |
| this.type = type; |
| this.column = column; |
| } |
| } |
| |
| // list of all properties in this group |
| private final Property[] mProperties; |
| |
| // list of columns for database query |
| private String[] mColumns; |
| |
| private static final String PATH_WHERE = Files.FileColumns.DATA + "=?"; |
| |
| // constructs a property group for a list of properties |
| public MtpPropertyGroup(int[] properties) { |
| int count = properties.length; |
| ArrayList<String> columns = new ArrayList<>(count); |
| columns.add(Files.FileColumns._ID); |
| |
| mProperties = new Property[count]; |
| for (int i = 0; i < count; i++) { |
| mProperties[i] = createProperty(properties[i], columns); |
| } |
| count = columns.size(); |
| mColumns = new String[count]; |
| for (int i = 0; i < count; i++) { |
| mColumns[i] = columns.get(i); |
| } |
| } |
| |
| private Property createProperty(int code, ArrayList<String> columns) { |
| String column = null; |
| int type; |
| |
| switch (code) { |
| case MtpConstants.PROPERTY_STORAGE_ID: |
| type = MtpConstants.TYPE_UINT32; |
| break; |
| case MtpConstants.PROPERTY_OBJECT_FORMAT: |
| type = MtpConstants.TYPE_UINT16; |
| break; |
| case MtpConstants.PROPERTY_PROTECTION_STATUS: |
| type = MtpConstants.TYPE_UINT16; |
| break; |
| case MtpConstants.PROPERTY_OBJECT_SIZE: |
| type = MtpConstants.TYPE_UINT64; |
| break; |
| case MtpConstants.PROPERTY_OBJECT_FILE_NAME: |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_NAME: |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_DATE_MODIFIED: |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_DATE_ADDED: |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE: |
| column = Audio.AudioColumns.YEAR; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_PARENT_OBJECT: |
| type = MtpConstants.TYPE_UINT32; |
| break; |
| case MtpConstants.PROPERTY_PERSISTENT_UID: |
| type = MtpConstants.TYPE_UINT128; |
| break; |
| case MtpConstants.PROPERTY_DURATION: |
| column = Audio.AudioColumns.DURATION; |
| type = MtpConstants.TYPE_UINT32; |
| break; |
| case MtpConstants.PROPERTY_TRACK: |
| column = Audio.AudioColumns.TRACK; |
| type = MtpConstants.TYPE_UINT16; |
| break; |
| case MtpConstants.PROPERTY_DISPLAY_NAME: |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_ARTIST: |
| column = Audio.AudioColumns.ARTIST; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_ALBUM_NAME: |
| column = Audio.AudioColumns.ALBUM; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_ALBUM_ARTIST: |
| column = Audio.AudioColumns.ALBUM_ARTIST; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_GENRE: |
| column = Audio.AudioColumns.GENRE; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_COMPOSER: |
| column = Audio.AudioColumns.COMPOSER; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_DESCRIPTION: |
| column = Images.ImageColumns.DESCRIPTION; |
| type = MtpConstants.TYPE_STR; |
| break; |
| case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC: |
| case MtpConstants.PROPERTY_AUDIO_BITRATE: |
| case MtpConstants.PROPERTY_SAMPLE_RATE: |
| // these are special cased |
| type = MtpConstants.TYPE_UINT32; |
| break; |
| case MtpConstants.PROPERTY_BITRATE_TYPE: |
| case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS: |
| // these are special cased |
| type = MtpConstants.TYPE_UINT16; |
| break; |
| default: |
| type = MtpConstants.TYPE_UNDEFINED; |
| Log.e(TAG, "unsupported property " + code); |
| break; |
| } |
| |
| if (column != null) { |
| columns.add(column); |
| return new Property(code, type, columns.size() - 1); |
| } else { |
| return new Property(code, type, -1); |
| } |
| } |
| |
| /** |
| * Gets the values of the properties represented by this property group for the given |
| * object and adds them to the given property list. |
| * @return Response_OK if the operation succeeded. |
| */ |
| public int getPropertyList(ContentProviderClient provider, String volumeName, |
| MtpStorageManager.MtpObject object, MtpPropertyList list) { |
| Cursor c = null; |
| int id = object.getId(); |
| String path = object.getPath().toString(); |
| for (Property property : mProperties) { |
| if (property.column != -1 && c == null) { |
| try { |
| // Look up the entry in MediaProvider only if one of those properties is needed. |
| final Uri uri = MtpDatabase.getObjectPropertiesUri(object.getFormat(), |
| volumeName); |
| c = provider.query(uri, mColumns, |
| PATH_WHERE, new String[] {path}, null, null); |
| if (c != null && !c.moveToNext()) { |
| c.close(); |
| c = null; |
| } |
| } catch (IllegalArgumentException e) { |
| return MtpConstants.RESPONSE_INVALID_OBJECT_PROP_CODE; |
| } catch (RemoteException e) { |
| Log.e(TAG, "Mediaprovider lookup failed"); |
| } |
| } |
| switch (property.code) { |
| case MtpConstants.PROPERTY_PROTECTION_STATUS: |
| // protection status is always 0 |
| list.append(id, property.code, property.type, 0); |
| break; |
| case MtpConstants.PROPERTY_NAME: |
| case MtpConstants.PROPERTY_OBJECT_FILE_NAME: |
| case MtpConstants.PROPERTY_DISPLAY_NAME: |
| list.append(id, property.code, object.getName()); |
| break; |
| case MtpConstants.PROPERTY_DATE_MODIFIED: |
| case MtpConstants.PROPERTY_DATE_ADDED: |
| // convert from seconds to DateTime |
| list.append(id, property.code, |
| format_date_time(object.getModifiedTime())); |
| break; |
| case MtpConstants.PROPERTY_STORAGE_ID: |
| list.append(id, property.code, property.type, object.getStorageId()); |
| break; |
| case MtpConstants.PROPERTY_OBJECT_FORMAT: |
| list.append(id, property.code, property.type, object.getFormat()); |
| break; |
| case MtpConstants.PROPERTY_OBJECT_SIZE: |
| list.append(id, property.code, property.type, object.getSize()); |
| break; |
| case MtpConstants.PROPERTY_PARENT_OBJECT: |
| list.append(id, property.code, property.type, |
| object.getParent().isRoot() ? 0 : object.getParent().getId()); |
| break; |
| case MtpConstants.PROPERTY_PERSISTENT_UID: |
| // The persistent uid must be unique and never reused among all objects, |
| // and remain the same between sessions. |
| long puid = (((long) object.getPath().toString().hashCode()) << 32) |
| + object.getModifiedTime(); |
| list.append(id, property.code, property.type, puid); |
| break; |
| case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE: |
| // release date is stored internally as just the year |
| int year = 0; |
| if (c != null) |
| year = c.getInt(property.column); |
| String dateTime = Integer.toString(year) + "0101T000000"; |
| list.append(id, property.code, dateTime); |
| break; |
| case MtpConstants.PROPERTY_TRACK: |
| int track = 0; |
| if (c != null) |
| track = c.getInt(property.column); |
| list.append(id, property.code, MtpConstants.TYPE_UINT16, |
| track % 1000); |
| break; |
| case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC: |
| case MtpConstants.PROPERTY_AUDIO_BITRATE: |
| case MtpConstants.PROPERTY_SAMPLE_RATE: |
| // we don't have these in our database, so return 0 |
| list.append(id, property.code, MtpConstants.TYPE_UINT32, 0); |
| break; |
| case MtpConstants.PROPERTY_BITRATE_TYPE: |
| case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS: |
| // we don't have these in our database, so return 0 |
| list.append(id, property.code, MtpConstants.TYPE_UINT16, 0); |
| break; |
| default: |
| switch(property.type) { |
| case MtpConstants.TYPE_UNDEFINED: |
| list.append(id, property.code, property.type, 0); |
| break; |
| case MtpConstants.TYPE_STR: |
| String value = ""; |
| if (c != null) |
| value = c.getString(property.column); |
| list.append(id, property.code, value); |
| break; |
| default: |
| long longValue = 0L; |
| if (c != null) |
| longValue = c.getLong(property.column); |
| list.append(id, property.code, property.type, longValue); |
| } |
| } |
| } |
| if (c != null) |
| c.close(); |
| return MtpConstants.RESPONSE_OK; |
| } |
| |
| private native String format_date_time(long seconds); |
| } |