Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b579f9d authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11420186 from bd68c079 to 24Q2-release

Change-Id: Iceb6e25382358d86f61eac1c4d562f80a4787c49
parents cdd75f17 bd68c079
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -74,7 +74,6 @@ import com.android.documentsui.roots.ProvidersCache;
import com.android.documentsui.sidebar.RootsFragment;
import com.android.documentsui.sorting.SortController;
import com.android.documentsui.sorting.SortModel;
import com.android.documentsui.util.FeatureFlagUtils;

import com.google.android.material.appbar.AppBarLayout;

@@ -104,6 +103,7 @@ public abstract class BaseActivity

    protected NavigationViewManager mNavigator;
    protected SortController mSortController;
    protected ConfigStore mConfigStore;

    private final List<EventListener> mEventListeners = new ArrayList<>();
    private final String mTag;
@@ -138,6 +138,16 @@ public abstract class BaseActivity

    public abstract Injector<?> getInjector();

    @VisibleForTesting
    protected void initConfigStore() {
        mConfigStore = DocumentsApplication.getConfigStore(this);
    }

    @VisibleForTesting
    public void setConfigStore(ConfigStore configStore) {
        mConfigStore = configStore;
    }

    @CallSuper
    @Override
    public void onCreate(Bundle savedInstanceState) {
@@ -159,6 +169,8 @@ public abstract class BaseActivity

        setContainer();

        initConfigStore();

        mInjector = getInjector();
        mState = getState(savedInstanceState);
        mDrawer = DrawerController.create(this, mInjector.config);
@@ -347,12 +359,14 @@ public abstract class BaseActivity

    private NavigationViewManager getNavigationViewManager(Breadcrumb breadcrumb,
            View profileTabsContainer) {
        if (FeatureFlagUtils.isPrivateSpaceEnabled()) {
        if (mConfigStore.isPrivateSpaceInDocsUIEnabled()) {
            return new NavigationViewManager(this, mDrawer, mState, this, breadcrumb,
                    profileTabsContainer, DocumentsApplication.getUserManagerState(this));
                    profileTabsContainer, DocumentsApplication.getUserManagerState(this),
                    mConfigStore);
        }
        return new NavigationViewManager(this, mDrawer, mState, this, breadcrumb,
                profileTabsContainer, DocumentsApplication.getUserIdManager(this));
                profileTabsContainer, DocumentsApplication.getUserIdManager(this),
                mConfigStore);
    }

    public void onPreferenceChanged(String pref) {
@@ -413,6 +427,7 @@ public abstract class BaseActivity
        mPreferencesMonitor.stop();
        mSortController.destroy();
        DocumentsApplication.invalidateUserManagerState(this);
        DocumentsApplication.invalidateConfigStore();
        super.onDestroy();
    }

@@ -438,6 +453,7 @@ public abstract class BaseActivity
                getApplicationContext()
                        .getResources()
                        .getBoolean(R.bool.show_hidden_files_by_default));
        state.configStore = mConfigStore;

        includeState(state);

+85 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.documentsui;

import android.os.Binder;
import android.provider.DeviceConfig;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.modules.utils.build.SdkLevel;

import com.google.common.base.Supplier;

public interface ConfigStore {
    // TODO(b/288066342): Remove and replace after new constant definition in
    //  {@link android.provider.DeviceConfig}.
    String NAMESPACE_MEDIAPROVIDER = "mediaprovider";

    boolean DEFAULT_PICKER_PRIVATE_SPACE_ENABLED = false;

    /**
     * @return if the Private-Space-in-DocsUI is enabled
     */
    default boolean isPrivateSpaceInDocsUIEnabled() {
        return DEFAULT_PICKER_PRIVATE_SPACE_ENABLED;
    }

    /**
     * Implementation of the {@link ConfigStore} that reads "real" configs from
     * {@link android.provider.DeviceConfig}. Meant to be used by the "production" code.
     */
    class ConfigStoreImpl implements ConfigStore {
        @VisibleForTesting
        public static final String KEY_PRIVATE_SPACE_FEATURE_ENABLED =
                "private_space_feature_enabled";

        private static final boolean sCanReadDeviceConfig = SdkLevel.isAtLeastS();

        private Boolean mIsPrivateSpaceEnabled = null;

        @Override
        public boolean isPrivateSpaceInDocsUIEnabled() {
            if (mIsPrivateSpaceEnabled == null) {
                mIsPrivateSpaceEnabled = getBooleanDeviceConfig(
                        NAMESPACE_MEDIAPROVIDER,
                        KEY_PRIVATE_SPACE_FEATURE_ENABLED,
                        DEFAULT_PICKER_PRIVATE_SPACE_ENABLED);
            }
            return sCanReadDeviceConfig && mIsPrivateSpaceEnabled;
        }

        private static boolean getBooleanDeviceConfig(@NonNull String namespace,
                @NonNull String key, boolean defaultValue) {
            if (!sCanReadDeviceConfig) {
                return defaultValue;
            }
            return withCleanCallingIdentity(
                    () -> DeviceConfig.getBoolean(namespace, key, defaultValue));
        }

        private static <T> T withCleanCallingIdentity(@NonNull Supplier<T> action) {
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                return action.get();
            } finally {
                Binder.restoreCallingIdentity(callingIdentity);
            }
        }
    }
}
+1 −2
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import com.android.documentsui.base.State;
import com.android.documentsui.base.UserId;
import com.android.documentsui.roots.RootCursorWrapper;
import com.android.documentsui.sorting.SortModel;
import com.android.documentsui.util.FeatureFlagUtils;

import java.util.ArrayList;
import java.util.List;
@@ -332,7 +331,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
    }

    private List<UserId> getUserIds() {
        if (FeatureFlagUtils.isPrivateSpaceEnabled()) {
        if (mState.configStore.isPrivateSpaceInDocsUIEnabled()) {
            return DocumentsApplication.getUserManagerState(getContext()).getUserIds();
        }
        return DocumentsApplication.getUserIdManager(getContext()).getUserIds();
+41 −6
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.os.RemoteException;
import android.text.format.DateUtils;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.android.documentsui.base.Lookup;
@@ -41,7 +42,6 @@ import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.queries.SearchHistoryManager;
import com.android.documentsui.roots.ProvidersCache;
import com.android.documentsui.theme.ThemeOverlayManager;
import com.android.documentsui.util.FeatureFlagUtils;
import com.android.modules.utils.build.SdkLevel;

import com.google.common.collect.Lists;
@@ -49,6 +49,8 @@ import com.google.common.collect.Lists;
import java.util.List;
import java.util.Objects;

import javax.annotation.concurrent.GuardedBy;

public class DocumentsApplication extends Application {
    private static final String TAG = "DocumentsApplication";
    private static final long PROVIDER_ANR_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS;
@@ -67,6 +69,10 @@ public class DocumentsApplication extends Application {
            Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE
    );

    @GuardedBy("DocumentsApplication.class")
    @Nullable
    private static volatile ConfigStore sConfigStore;

    private ProvidersCache mProviders;
    private ThumbnailCache mThumbnailCache;
    private ClipStorage mClipStore;
@@ -127,13 +133,33 @@ public class DocumentsApplication extends Application {
    }

    /**
     * Set mUserManagerState as null onDestroy of BaseActivity so that new session uses new instance
     * of mUserManagerState
     * Set {@link #mUserManagerState} as null onDestroy of BaseActivity so that new session uses new
     * instance of {@link #mUserManagerState}
     */
    public static void invalidateUserManagerState(Context context) {
        ((DocumentsApplication) context.getApplicationContext()).mUserManagerState = null;
    }

    /**
     * Retrieve {@link ConfigStore} instance to access feature flags in production code.
     */
    public static synchronized ConfigStore getConfigStore(Context context) {
        if (sConfigStore == null) {
            sConfigStore = new ConfigStore.ConfigStoreImpl();
        }
        return sConfigStore;
    }

    /**
     * Set {@link #sConfigStore} as null onDestroy of BaseActivity so that new session uses new
     * instance of {@link #sConfigStore}
     */
    public static void invalidateConfigStore() {
        synchronized (DocumentsApplication.class) {
            sConfigStore = null;
        }
    }

    private void onApplyOverlayFinish(boolean result) {
        Log.d(TAG, "OverlayManager.setEnabled() result: " + result);
    }
@@ -142,6 +168,11 @@ public class DocumentsApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        synchronized (DocumentsApplication.class) {
            if (sConfigStore == null) {
                sConfigStore = new ConfigStore.ConfigStoreImpl();
            }
        }

        final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        final OverlayManager om = getSystemService(OverlayManager.class);
@@ -154,14 +185,18 @@ public class DocumentsApplication extends Application {
            Log.w(TAG, "Can't obtain OverlayManager from System Service!");
        }

        if (FeatureFlagUtils.isPrivateSpaceEnabled()) {
        if (getConfigStore(this).isPrivateSpaceInDocsUIEnabled()) {
            mUserManagerState = UserManagerState.create(this);
            mUserIdManager = null;
            mProviders = new ProvidersCache(this, mUserManagerState);
            synchronized (DocumentsApplication.class) {
                mProviders = new ProvidersCache(this, mUserManagerState, sConfigStore);
            }
        } else {
            mUserManagerState = null;
            mUserIdManager = UserIdManager.create(this);
            mProviders = new ProvidersCache(this, mUserIdManager);
            synchronized (DocumentsApplication.class) {
                mProviders = new ProvidersCache(this, mUserIdManager, sConfigStore);
            }
        }

        mProviders.updateAsync(/* forceRefreshAll= */ false, /* callback= */  null);
+1 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ public final class HorizontalBreadcrumb extends RecyclerView implements Breadcru
        mLayoutManager = new HorizontalBreadcrumbLinearLayoutManager(
                getContext(), LinearLayoutManager.HORIZONTAL, false);
        mAdapter = new BreadcrumbAdapter(state, env, this::onKey);
        mAdapter.setHasStableIds(true);
        // Since we are using GestureDetector to detect click events, a11y services don't know which
        // views are clickable because we aren't using View.OnClickListener. Thus, we need to use a
        // custom accessibility delegate to route click events correctly.
Loading