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