123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan/* 223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * Copyright (C) 2017 The Android Open Source Project 323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * 423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * Licensed under the Apache License, Version 2.0 (the "License"); 523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * you may not use this file except in compliance with the License. 623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * You may obtain a copy of the License at 723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * 823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * http://www.apache.org/licenses/LICENSE-2.0 923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * 1023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * Unless required by applicable law or agreed to in writing, software 1123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * distributed under the License is distributed on an "AS IS" BASIS, 1223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * See the License for the specific language governing permissions and 1423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * limitations under the License. 1523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan */ 1623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 1723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanpackage com.android.documentsui.picker; 1823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 1923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport android.app.Activity; 2023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport android.content.ContentResolver; 2123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport android.content.ContentValues; 2223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport android.database.Cursor; 2323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport android.net.Uri; 2423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport android.util.Log; 2523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 2623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport com.android.documentsui.base.DocumentStack; 2723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport com.android.documentsui.base.Shared; 2823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport com.android.documentsui.base.State; 299bd4099ee27f8302a06fc66980079f29127318f8Jon Mannimport com.android.documentsui.roots.ProvidersAccess; 3023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 3123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport libcore.io.IoUtils; 3223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 3323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport java.io.IOException; 3423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 3523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanimport javax.annotation.Nullable; 3623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 3723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan/** 3823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan * An interface that stores the last accessed stack of the caller 3923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan */ 4023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tanpublic interface LastAccessedStorage { 4123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 4223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan @Nullable DocumentStack getLastAccessed( 439bd4099ee27f8302a06fc66980079f29127318f8Jon Mann Activity activity, ProvidersAccess providers, State state); 4423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 4523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan void setLastAccessed(Activity activity, DocumentStack stack); 4623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 4723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan void setLastAccessedToExternalApp(Activity activity); 4823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 4923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan static LastAccessedStorage create() { 5023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan return new RuntimeLastAccessedStorage(); 5123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } 5223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 5323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan class RuntimeLastAccessedStorage implements LastAccessedStorage { 5423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 5523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan private static final String TAG = "LastAccessedStorage"; 5623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 5723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan private RuntimeLastAccessedStorage() {} 5823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 5923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan @Override 6023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan public @Nullable DocumentStack getLastAccessed( 619bd4099ee27f8302a06fc66980079f29127318f8Jon Mann Activity activity, ProvidersAccess providers, State state) { 6223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan final String packageName = Shared.getCallingPackageName(activity); 6323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan final Uri resumeUri = LastAccessedProvider.buildLastAccessed(packageName); 6423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan final ContentResolver resolver = activity.getContentResolver(); 6523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan Cursor cursor = resolver.query(resumeUri, null, null, null, null); 6623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan try { 6723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan return DocumentStack.fromLastAccessedCursor( 689bd4099ee27f8302a06fc66980079f29127318f8Jon Mann cursor, providers.getMatchingRootsBlocking(state), resolver); 6923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } catch (IOException e) { 7023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan Log.w(TAG, "Failed to resume: ", e); 7123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } finally { 7223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan IoUtils.closeQuietly(cursor); 7323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } 7423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 7523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan return null; 7623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } 7723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 7823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan @Override 7923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan public void setLastAccessed(Activity activity, DocumentStack stack) { 8023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan String packageName = Shared.getCallingPackageName(activity); 8123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan LastAccessedProvider.setLastAccessed(activity.getContentResolver(), packageName, stack); 8223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } 8323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan 8423ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan @Override 8523ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan public void setLastAccessedToExternalApp(Activity activity) { 8623ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan final String packageName = Shared.getCallingPackageName(activity); 8723ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan final ContentValues values = new ContentValues(); 8823ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan values.put(LastAccessedProvider.Columns.EXTERNAL, 1); 8923ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan activity.getContentResolver().insert( 9023ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan LastAccessedProvider.buildLastAccessed(packageName), values); 9123ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } 9223ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan } 9323ac60cd2b1beb59b6cd760b91c7e1b1f7e8fe49Garfield Tan} 94