1 /* 2 * Copyright (C) 2015 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 com.android.mtp; 18 19 import android.annotation.IntDef; 20 import android.database.sqlite.SQLiteQueryBuilder; 21 import android.provider.DocumentsContract.Document; 22 import android.provider.DocumentsContract.Root; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.util.HashMap; 27 import java.util.Map; 28 29 /** 30 * Class containing MtpDatabase constants. 31 */ 32 class MtpDatabaseConstants { 33 static final int DATABASE_VERSION = 5; 34 static final String DATABASE_NAME = "database"; 35 36 static final int FLAG_DATABASE_IN_MEMORY = 1; 37 static final int FLAG_DATABASE_IN_FILE = 0; 38 39 /** 40 * Table representing documents including root documents. 41 */ 42 static final String TABLE_DOCUMENTS = "Documents"; 43 44 /** 45 * Table containing additional information only available for root documents. 46 * The table uses same primary keys with corresponding documents. 47 */ 48 static final String TABLE_ROOT_EXTRA = "RootExtra"; 49 50 /** 51 * Table containing last boot count. 52 */ 53 static final String TABLE_LAST_BOOT_COUNT = "LastBootCount"; 54 55 /** 56 * 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA. 57 */ 58 static final String JOIN_ROOTS = createJoinFromClosure( 59 TABLE_DOCUMENTS, 60 TABLE_ROOT_EXTRA, 61 Document.COLUMN_DOCUMENT_ID, 62 Root.COLUMN_ROOT_ID); 63 64 static final String COLUMN_DEVICE_ID = "device_id"; 65 static final String COLUMN_STORAGE_ID = "storage_id"; 66 static final String COLUMN_OBJECT_HANDLE = "object_handle"; 67 static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id"; 68 static final String COLUMN_DOCUMENT_TYPE = "document_type"; 69 static final String COLUMN_ROW_STATE = "row_state"; 70 static final String COLUMN_MAPPING_KEY = "mapping_key"; 71 72 /** 73 * Value for TABLE_LAST_BOOT_COUNT. 74 * Type: INTEGER 75 */ 76 static final String COLUMN_VALUE = "value"; 77 78 /** 79 * The state represents that the row has a valid object handle. 80 */ 81 static final int ROW_STATE_VALID = 0; 82 83 /** 84 * The state represents that the rows added at the previous cycle and need to be updated with 85 * fresh values. 86 * The row may not have valid object handle. External application can still fetch the documents. 87 * If the external application tries to fetch object handle, the provider resolves pending 88 * documents with invalidated documents ahead. 89 */ 90 static final int ROW_STATE_INVALIDATED = 1; 91 92 /** 93 * The documents are of device/storage that are disconnected now. The documents are invisible 94 * but their document ID will be reuse when the device/storage is connected again. 95 */ 96 static final int ROW_STATE_DISCONNECTED = 2; 97 98 @IntDef(value = { DOCUMENT_TYPE_DEVICE, DOCUMENT_TYPE_STORAGE, DOCUMENT_TYPE_OBJECT }) 99 @Retention(RetentionPolicy.SOURCE) 100 public @interface DocumentType {} 101 102 /** 103 * Document that represents a MTP device. 104 */ 105 static final int DOCUMENT_TYPE_DEVICE = 0; 106 107 /** 108 * Document that represents a MTP storage. 109 */ 110 static final int DOCUMENT_TYPE_STORAGE = 1; 111 112 /** 113 * Document that represents a MTP object. 114 */ 115 static final int DOCUMENT_TYPE_OBJECT = 2; 116 117 static final String SELECTION_DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID + " = ?"; 118 static final String SELECTION_ROOT_ID = Root.COLUMN_ROOT_ID + " = ?"; 119 120 static final String QUERY_CREATE_DOCUMENTS = 121 "CREATE TABLE " + TABLE_DOCUMENTS + " (" + 122 Document.COLUMN_DOCUMENT_ID + 123 " INTEGER PRIMARY KEY AUTOINCREMENT," + 124 COLUMN_DEVICE_ID + " INTEGER," + 125 COLUMN_STORAGE_ID + " INTEGER," + 126 COLUMN_OBJECT_HANDLE + " INTEGER," + 127 COLUMN_PARENT_DOCUMENT_ID + " INTEGER," + 128 COLUMN_ROW_STATE + " INTEGER NOT NULL," + 129 COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," + 130 COLUMN_MAPPING_KEY + " STRING," + 131 Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," + 132 Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," + 133 Document.COLUMN_SUMMARY + " TEXT," + 134 Document.COLUMN_LAST_MODIFIED + " INTEGER," + 135 Document.COLUMN_ICON + " INTEGER," + 136 Document.COLUMN_FLAGS + " INTEGER NOT NULL," + 137 Document.COLUMN_SIZE + " INTEGER);"; 138 139 static final String QUERY_CREATE_ROOT_EXTRA = 140 "CREATE TABLE " + TABLE_ROOT_EXTRA + " (" + 141 Root.COLUMN_ROOT_ID + " INTEGER PRIMARY KEY," + 142 Root.COLUMN_FLAGS + " INTEGER NOT NULL," + 143 Root.COLUMN_AVAILABLE_BYTES + " INTEGER," + 144 Root.COLUMN_CAPACITY_BYTES + " INTEGER," + 145 Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);"; 146 147 static final String QUERY_CREATE_LAST_BOOT_COUNT = 148 "CREATE TABLE " + TABLE_LAST_BOOT_COUNT + " (value INTEGER NOT NULL);"; 149 150 /** 151 * Map for columns names to provide DocumentContract.Root compatible columns. 152 * @see SQLiteQueryBuilder#setProjectionMap(Map) 153 */ 154 static final Map<String, String> COLUMN_MAP_ROOTS; 155 static { 156 COLUMN_MAP_ROOTS = new HashMap<>(); COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID)157 COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID); COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS)158 COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS); COLUMN_MAP_ROOTS.put( Root.COLUMN_ICON, TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON)159 COLUMN_MAP_ROOTS.put( 160 Root.COLUMN_ICON, 161 TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON); COLUMN_MAP_ROOTS.put( Root.COLUMN_TITLE, TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE)162 COLUMN_MAP_ROOTS.put( 163 Root.COLUMN_TITLE, 164 TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE); COLUMN_MAP_ROOTS.put( Root.COLUMN_SUMMARY, TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY)165 COLUMN_MAP_ROOTS.put( 166 Root.COLUMN_SUMMARY, 167 TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY); COLUMN_MAP_ROOTS.put( Root.COLUMN_DOCUMENT_ID, TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " + Root.COLUMN_DOCUMENT_ID)168 COLUMN_MAP_ROOTS.put( 169 Root.COLUMN_DOCUMENT_ID, 170 TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + 171 " AS " + Root.COLUMN_DOCUMENT_ID); COLUMN_MAP_ROOTS.put( Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES)172 COLUMN_MAP_ROOTS.put( 173 Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES); COLUMN_MAP_ROOTS.put( Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES)174 COLUMN_MAP_ROOTS.put( 175 Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES); COLUMN_MAP_ROOTS.put( Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES)176 COLUMN_MAP_ROOTS.put( 177 Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES); COLUMN_MAP_ROOTS.put(COLUMN_DEVICE_ID, COLUMN_DEVICE_ID)178 COLUMN_MAP_ROOTS.put(COLUMN_DEVICE_ID, COLUMN_DEVICE_ID); 179 } 180 createJoinFromClosure( String table1, String table2, String column1, String column2)181 private static String createJoinFromClosure( 182 String table1, String table2, String column1, String column2) { 183 return table1 + " LEFT JOIN " + table2 + 184 " ON " + table1 + "." + column1 + " = " + table2 + "." + column2; 185 } 186 } 187