1
+ package com .android .vending .expansion .zipfile ;
2
+
3
+ /*
4
+ * Copyright (C) 2012 The Android Open Source Project
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ //To implement APEZProvider in your application, you'll want to change
20
+ //the AUTHORITY to match what you define in the manifest.
21
+
22
+ import com .android .vending .expansion .zipfile .ZipResourceFile .ZipEntryRO ;
23
+
24
+ import android .content .ContentProvider ;
25
+ import android .content .ContentProviderOperation ;
26
+ import android .content .ContentProviderResult ;
27
+ import android .content .ContentValues ;
28
+ import android .content .Context ;
29
+ import android .content .OperationApplicationException ;
30
+ import android .content .pm .PackageInfo ;
31
+ import android .content .pm .PackageManager ;
32
+ import android .content .pm .PackageManager .NameNotFoundException ;
33
+ import android .content .pm .ProviderInfo ;
34
+ import android .content .res .AssetFileDescriptor ;
35
+ import android .database .Cursor ;
36
+ import android .database .MatrixCursor ;
37
+ import android .net .Uri ;
38
+ import android .os .ParcelFileDescriptor ;
39
+ import android .provider .BaseColumns ;
40
+
41
+ import java .io .FileNotFoundException ;
42
+ import java .io .IOException ;
43
+ import java .util .ArrayList ;
44
+
45
+ /**
46
+ * This content provider is an optional part of the library.
47
+ *
48
+ * <p>Most apps don't need to use this class. This defines a
49
+ * ContentProvider that marshalls the data from the ZIP files through a
50
+ * content provider Uri in order to provide file access for certain Android APIs
51
+ * that expect Uri access to media files.
52
+ *
53
+ */
54
+ public abstract class APEZProvider extends ContentProvider {
55
+
56
+ private ZipResourceFile mAPKExtensionFile ;
57
+ private boolean mInit ;
58
+
59
+ public static final String FILEID = BaseColumns ._ID ;
60
+ public static final String FILENAME = "ZPFN" ;
61
+ public static final String ZIPFILE = "ZFIL" ;
62
+ public static final String MODIFICATION = "ZMOD" ;
63
+ public static final String CRC32 = "ZCRC" ;
64
+ public static final String COMPRESSEDLEN = "ZCOL" ;
65
+ public static final String UNCOMPRESSEDLEN = "ZUNL" ;
66
+ public static final String COMPRESSIONTYPE = "ZTYP" ;
67
+
68
+ public static final String [] ALL_FIELDS = {
69
+ FILEID ,
70
+ FILENAME ,
71
+ ZIPFILE ,
72
+ MODIFICATION ,
73
+ CRC32 ,
74
+ COMPRESSEDLEN ,
75
+ UNCOMPRESSEDLEN ,
76
+ COMPRESSIONTYPE
77
+ };
78
+
79
+ public static final int FILEID_IDX = 0 ;
80
+ public static final int FILENAME_IDX = 1 ;
81
+ public static final int ZIPFILE_IDX = 2 ;
82
+ public static final int MOD_IDX = 3 ;
83
+ public static final int CRC_IDX = 4 ;
84
+ public static final int COMPLEN_IDX = 5 ;
85
+ public static final int UNCOMPLEN_IDX = 6 ;
86
+ public static final int COMPTYPE_IDX = 7 ;
87
+
88
+ public static final int [] ALL_FIELDS_INT = {
89
+ FILEID_IDX ,
90
+ FILENAME_IDX ,
91
+ ZIPFILE_IDX ,
92
+ MOD_IDX ,
93
+ CRC_IDX ,
94
+ COMPLEN_IDX ,
95
+ UNCOMPLEN_IDX ,
96
+ COMPTYPE_IDX
97
+ };
98
+
99
+ /**
100
+ * This needs to match the authority in your manifest
101
+ */
102
+ public abstract String getAuthority ();
103
+
104
+ @ Override
105
+ public int delete (Uri arg0 , String arg1 , String [] arg2 ) {
106
+ // TODO Auto-generated method stub
107
+ return 0 ;
108
+ }
109
+
110
+ @ Override
111
+ public String getType (Uri uri ) {
112
+ return "vnd.android.cursor.item/asset" ;
113
+ }
114
+
115
+ @ Override
116
+ public Uri insert (Uri uri , ContentValues values ) {
117
+ // TODO Auto-generated method stub
118
+ return null ;
119
+ }
120
+
121
+ static private final String NO_FILE = "N" ;
122
+
123
+ private boolean initIfNecessary () {
124
+ if ( !mInit ) {
125
+ Context ctx = getContext ();
126
+ PackageManager pm = ctx .getPackageManager ();
127
+ ProviderInfo pi = pm .resolveContentProvider (getAuthority (), PackageManager .GET_META_DATA );
128
+ PackageInfo packInfo ;
129
+ try {
130
+ packInfo = pm .getPackageInfo (ctx .getPackageName (), 0 );
131
+ } catch (NameNotFoundException e1 ) {
132
+ e1 .printStackTrace ();
133
+ return false ;
134
+ }
135
+ int patchFileVersion ;
136
+ int mainFileVersion ;
137
+ int appVersionCode = packInfo .versionCode ;
138
+ String [] resourceFiles = null ;
139
+ if ( null != pi .metaData ) {
140
+ mainFileVersion = pi .metaData .getInt ("mainVersion" , appVersionCode );
141
+ patchFileVersion = pi .metaData .getInt ("patchVersion" , appVersionCode );
142
+ String mainFileName = pi .metaData .getString ("mainFilename" , NO_FILE );
143
+ if ( NO_FILE != mainFileName ) {
144
+ String patchFileName = pi .metaData .getString ("patchFilename" , NO_FILE );
145
+ if ( NO_FILE != patchFileName ) {
146
+ resourceFiles = new String [] { mainFileName , patchFileName };
147
+ } else {
148
+ resourceFiles = new String [] { mainFileName };
149
+ }
150
+ }
151
+ } else {
152
+ mainFileVersion = patchFileVersion = appVersionCode ;
153
+ }
154
+ try {
155
+ if ( null == resourceFiles ) {
156
+ mAPKExtensionFile = APKExpansionSupport .getAPKExpansionZipFile (ctx , mainFileVersion , patchFileVersion );
157
+ } else {
158
+ mAPKExtensionFile = APKExpansionSupport .getResourceZipFile (resourceFiles );
159
+ }
160
+ mInit = true ;
161
+ return true ;
162
+ } catch (IOException e ) {
163
+ e .printStackTrace ();
164
+ }
165
+ }
166
+ return false ;
167
+ }
168
+
169
+ @ Override
170
+ public boolean onCreate () {
171
+ return true ;
172
+ }
173
+
174
+ @ Override
175
+ public AssetFileDescriptor openAssetFile (Uri uri , String mode )
176
+ throws FileNotFoundException {
177
+ initIfNecessary ();
178
+ String path = uri .getEncodedPath ();
179
+ if ( path .startsWith ("/" ) ) {
180
+ path = path .substring (1 );
181
+ }
182
+ return mAPKExtensionFile .getAssetFileDescriptor (path );
183
+ }
184
+
185
+ @ Override
186
+ public ContentProviderResult [] applyBatch (
187
+ ArrayList <ContentProviderOperation > operations )
188
+ throws OperationApplicationException {
189
+ initIfNecessary ();
190
+ return super .applyBatch (operations );
191
+ }
192
+
193
+ @ Override
194
+ public ParcelFileDescriptor openFile (Uri uri , String mode )
195
+ throws FileNotFoundException {
196
+ initIfNecessary ();
197
+ AssetFileDescriptor af = openAssetFile (uri , mode );
198
+ if ( null != af ) {
199
+ return af .getParcelFileDescriptor ();
200
+ }
201
+ return null ;
202
+ }
203
+
204
+ @ Override
205
+ public Cursor query (Uri uri , String [] projection , String selection ,
206
+ String [] selectionArgs , String sortOrder ) {
207
+ initIfNecessary ();
208
+ // lists all of the items in the file that match
209
+ ZipEntryRO [] zipEntries ;
210
+ if ( null == mAPKExtensionFile ) {
211
+ zipEntries = new ZipEntryRO [0 ];
212
+ } else {
213
+ zipEntries = mAPKExtensionFile .getAllEntries ();
214
+ }
215
+ int [] intProjection ;
216
+ if ( null == projection ) {
217
+ intProjection = ALL_FIELDS_INT ;
218
+ projection = ALL_FIELDS ;
219
+ } else {
220
+ int len = projection .length ;
221
+ intProjection = new int [len ];
222
+ for ( int i = 0 ; i < len ; i ++ ) {
223
+ if ( projection [i ].equals (FILEID ) ) {
224
+ intProjection [i ] = FILEID_IDX ;
225
+ } else if ( projection [i ].equals (FILENAME ) ) {
226
+ intProjection [i ] = FILENAME_IDX ;
227
+ } else if ( projection [i ].equals (ZIPFILE ) ) {
228
+ intProjection [i ] = ZIPFILE_IDX ;
229
+ } else if ( projection [i ].equals (MODIFICATION ) ) {
230
+ intProjection [i ] = MOD_IDX ;
231
+ } else if ( projection [i ].equals (CRC32 ) ) {
232
+ intProjection [i ] = CRC_IDX ;
233
+ } else if ( projection [i ].equals (COMPRESSEDLEN ) ) {
234
+ intProjection [i ] = COMPLEN_IDX ;
235
+ } else if ( projection [i ].equals (UNCOMPRESSEDLEN ) ) {
236
+ intProjection [i ] = UNCOMPLEN_IDX ;
237
+ } else if ( projection [i ].equals (COMPRESSIONTYPE ) ) {
238
+ intProjection [i ] = COMPTYPE_IDX ;
239
+ } else {
240
+ throw new RuntimeException ();
241
+ }
242
+ }
243
+ }
244
+ MatrixCursor mc = new MatrixCursor (projection , zipEntries .length );
245
+ int len = intProjection .length ;
246
+ for ( ZipEntryRO zer : zipEntries ) {
247
+ MatrixCursor .RowBuilder rb = mc .newRow ();
248
+ for ( int i = 0 ; i < len ; i ++ ) {
249
+ switch (intProjection [i ]) {
250
+ case FILEID_IDX :
251
+ rb .add (i );
252
+ break ;
253
+ case FILENAME_IDX :
254
+ rb .add (zer .mFileName );
255
+ break ;
256
+ case ZIPFILE_IDX :
257
+ rb .add (zer .getZipFileName ());
258
+ break ;
259
+ case MOD_IDX :
260
+ rb .add (zer .mWhenModified );
261
+ break ;
262
+ case CRC_IDX :
263
+ rb .add (zer .mCRC32 );
264
+ break ;
265
+ case COMPLEN_IDX :
266
+ rb .add (zer .mCompressedLength );
267
+ break ;
268
+ case UNCOMPLEN_IDX :
269
+ rb .add (zer .mUncompressedLength );
270
+ break ;
271
+ case COMPTYPE_IDX :
272
+ rb .add (zer .mMethod );
273
+ break ;
274
+ }
275
+ }
276
+ }
277
+ return mc ;
278
+ }
279
+
280
+ @ Override
281
+ public int update (Uri uri , ContentValues values , String selection ,
282
+ String [] selectionArgs ) {
283
+ // TODO Auto-generated method stub
284
+ return 0 ;
285
+ }
286
+
287
+ }
0 commit comments