Loading src/com/android/documentsui/dirlist/DirectoryFragment.java +90 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.documentsui.base.State.MODE_LIST; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading @@ -31,6 +32,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Parcelable; import android.os.UserHandle; import android.provider.DocumentsContract; Loading Loading @@ -136,6 +138,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private static final int CACHE_EVICT_LIMIT = 100; private static final int REFRESH_SPINNER_TIMEOUT = 500; private static final int PROVIDER_MAX_RETRIES = 10; private static final long PROVIDER_TEST_DELAY = 4000; private BaseActivity mActivity; Loading Loading @@ -190,6 +194,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private DirectoryState mLocalState; private Handler mHandler; private Runnable mProviderTestRunnable; // Note, we use !null to indicate that selection was restored (from rotation). // So don't fiddle with this field unless you've got the bigger picture in mind. private @Nullable Bundle mRestoredState; Loading Loading @@ -225,15 +232,91 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On final String action = intent.getAction(); if (isManagedProfileAction(action)) { UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); if (Objects.equal(mActivity.getSelectedUser(), UserId.of(userHandle))) { UserId userId = UserId.of(userHandle); if (Objects.equal(mActivity.getSelectedUser(), userId)) { // We only need to refresh the layout when the selected user is equal to the // received profile user. if (Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) { // If the managed profile is turned off, we need to refresh the directory // to update the UI to show an appropriate error message. if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); mProviderTestRunnable = null; } onRefresh(); return; } // When the managed profile becomes available, the provider may not be available // immediately, we need to check if it is ready before we reload the content. if (Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) { checkUriAndScheduleCheckIfNeeded(userId); } } } } }; private void checkUriAndScheduleCheckIfNeeded(UserId userId) { RootInfo currentRoot = mActivity.getCurrentRoot(); DocumentInfo currentDoc = mActivity.getDisplayState().stack.peek(); Uri uri = getCurrentUri(currentRoot, currentDoc); if (isProviderAvailable(uri, userId) || mActivity.isInRecents()) { if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); mProviderTestRunnable = null; } mHandler.post(() -> onRefresh()); } else { checkUriWithDelay(/* numOfRetries= */1, uri, userId); } } private void checkUriWithDelay(int numOfRetries, Uri uri, UserId userId) { mProviderTestRunnable = () -> { RootInfo currentRoot = mActivity.getCurrentRoot(); DocumentInfo currentDoc = mActivity.getDisplayState().stack.peek(); if (mActivity.getSelectedUser().equals(userId) && uri.equals(getCurrentUri(currentRoot, currentDoc))) { if (isProviderAvailable(uri, userId) || userId.isQuietModeEnabled(mActivity) || numOfRetries >= PROVIDER_MAX_RETRIES) { // We stop the recursive check when // 1. the provider is available // 2. the profile is in quiet mode, i.e. provider will not be available // 3. after maximum retries onRefresh(); mProviderTestRunnable = null; } else { Log.d(TAG, "Provider is not available. Retry after " + PROVIDER_TEST_DELAY); checkUriWithDelay(numOfRetries + 1, uri, userId); } } }; mHandler.postDelayed(mProviderTestRunnable, PROVIDER_TEST_DELAY); } private Uri getCurrentUri(RootInfo root, @Nullable DocumentInfo doc) { String authority = doc == null ? root.authority : doc.authority; String documentId = doc == null ? root.documentId : doc.documentId; return DocumentsContract.buildDocumentUri(authority, documentId); } private boolean isProviderAvailable(Uri uri, UserId userId) { try (ContentProviderClient userClient = DocumentsApplication.acquireUnstableProviderOrThrow( userId.getContentResolver(mActivity), uri.getAuthority())) { Cursor testCursor = userClient.query(uri, /* projection= */ null, /* queryArgs= */null, /* cancellationSignal= */ null); if (testCursor != null) { return true; } } catch (Exception e) { // Provider is not available. Ignore. } return false; } private static boolean isManagedProfileAction(String action) { return Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action) || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action); Loading @@ -243,6 +326,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mHandler = new Handler(Looper.getMainLooper()); mActivity = (BaseActivity) getActivity(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); Loading Loading @@ -302,6 +386,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mInjector.actions.unregisterDisplayStateChangedListener(mOnDisplayStateChanged); if (mState.supportsCrossProfile()) { LocalBroadcastManager.getInstance(mActivity).unregisterReceiver(mReceiver); if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); } } // Cancel any outstanding thumbnail requests Loading Loading @@ -1206,7 +1293,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On } final DocumentInfo doc = mActivity.getCurrentDirectory(); if (doc == null) { if (doc == null && !mActivity.getSelectedUser().isQuietModeEnabled(mActivity)) { // If there is no root doc, try to reload the root doc from root info. Log.w(TAG, "No root document. Try to get root document."); getRootDocumentAndMaybeRefreshDocument(); Loading Loading
src/com/android/documentsui/dirlist/DirectoryFragment.java +90 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.documentsui.base.State.MODE_LIST; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading @@ -31,6 +32,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Parcelable; import android.os.UserHandle; import android.provider.DocumentsContract; Loading Loading @@ -136,6 +138,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private static final int CACHE_EVICT_LIMIT = 100; private static final int REFRESH_SPINNER_TIMEOUT = 500; private static final int PROVIDER_MAX_RETRIES = 10; private static final long PROVIDER_TEST_DELAY = 4000; private BaseActivity mActivity; Loading Loading @@ -190,6 +194,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private DirectoryState mLocalState; private Handler mHandler; private Runnable mProviderTestRunnable; // Note, we use !null to indicate that selection was restored (from rotation). // So don't fiddle with this field unless you've got the bigger picture in mind. private @Nullable Bundle mRestoredState; Loading Loading @@ -225,15 +232,91 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On final String action = intent.getAction(); if (isManagedProfileAction(action)) { UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); if (Objects.equal(mActivity.getSelectedUser(), UserId.of(userHandle))) { UserId userId = UserId.of(userHandle); if (Objects.equal(mActivity.getSelectedUser(), userId)) { // We only need to refresh the layout when the selected user is equal to the // received profile user. if (Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) { // If the managed profile is turned off, we need to refresh the directory // to update the UI to show an appropriate error message. if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); mProviderTestRunnable = null; } onRefresh(); return; } // When the managed profile becomes available, the provider may not be available // immediately, we need to check if it is ready before we reload the content. if (Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) { checkUriAndScheduleCheckIfNeeded(userId); } } } } }; private void checkUriAndScheduleCheckIfNeeded(UserId userId) { RootInfo currentRoot = mActivity.getCurrentRoot(); DocumentInfo currentDoc = mActivity.getDisplayState().stack.peek(); Uri uri = getCurrentUri(currentRoot, currentDoc); if (isProviderAvailable(uri, userId) || mActivity.isInRecents()) { if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); mProviderTestRunnable = null; } mHandler.post(() -> onRefresh()); } else { checkUriWithDelay(/* numOfRetries= */1, uri, userId); } } private void checkUriWithDelay(int numOfRetries, Uri uri, UserId userId) { mProviderTestRunnable = () -> { RootInfo currentRoot = mActivity.getCurrentRoot(); DocumentInfo currentDoc = mActivity.getDisplayState().stack.peek(); if (mActivity.getSelectedUser().equals(userId) && uri.equals(getCurrentUri(currentRoot, currentDoc))) { if (isProviderAvailable(uri, userId) || userId.isQuietModeEnabled(mActivity) || numOfRetries >= PROVIDER_MAX_RETRIES) { // We stop the recursive check when // 1. the provider is available // 2. the profile is in quiet mode, i.e. provider will not be available // 3. after maximum retries onRefresh(); mProviderTestRunnable = null; } else { Log.d(TAG, "Provider is not available. Retry after " + PROVIDER_TEST_DELAY); checkUriWithDelay(numOfRetries + 1, uri, userId); } } }; mHandler.postDelayed(mProviderTestRunnable, PROVIDER_TEST_DELAY); } private Uri getCurrentUri(RootInfo root, @Nullable DocumentInfo doc) { String authority = doc == null ? root.authority : doc.authority; String documentId = doc == null ? root.documentId : doc.documentId; return DocumentsContract.buildDocumentUri(authority, documentId); } private boolean isProviderAvailable(Uri uri, UserId userId) { try (ContentProviderClient userClient = DocumentsApplication.acquireUnstableProviderOrThrow( userId.getContentResolver(mActivity), uri.getAuthority())) { Cursor testCursor = userClient.query(uri, /* projection= */ null, /* queryArgs= */null, /* cancellationSignal= */ null); if (testCursor != null) { return true; } } catch (Exception e) { // Provider is not available. Ignore. } return false; } private static boolean isManagedProfileAction(String action) { return Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action) || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action); Loading @@ -243,6 +326,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mHandler = new Handler(Looper.getMainLooper()); mActivity = (BaseActivity) getActivity(); final View view = inflater.inflate(R.layout.fragment_directory, container, false); Loading Loading @@ -302,6 +386,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mInjector.actions.unregisterDisplayStateChangedListener(mOnDisplayStateChanged); if (mState.supportsCrossProfile()) { LocalBroadcastManager.getInstance(mActivity).unregisterReceiver(mReceiver); if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); } } // Cancel any outstanding thumbnail requests Loading Loading @@ -1206,7 +1293,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On } final DocumentInfo doc = mActivity.getCurrentDirectory(); if (doc == null) { if (doc == null && !mActivity.getSelectedUser().isQuietModeEnabled(mActivity)) { // If there is no root doc, try to reload the root doc from root info. Log.w(TAG, "No root document. Try to get root document."); getRootDocumentAndMaybeRefreshDocument(); Loading