1d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay/*
2d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * Copyright (C) 2015 The Android Open Source Project
3d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay *
4d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * Licensed under the Apache License, Version 2.0 (the "License");
5d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * you may not use this file except in compliance with the License.
6d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * You may obtain a copy of the License at
7d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay *
8d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay *      http://www.apache.org/licenses/LICENSE-2.0
9d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay *
10d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * Unless required by applicable law or agreed to in writing, software
11d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * distributed under the License is distributed on an "AS IS" BASIS,
12d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * See the License for the specific language governing permissions and
14d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay * limitations under the License.
15d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay */
16d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
17b6006b2ef723fdbb3fef3b4a350c8d363b127d0fSteve McKaypackage com.android.documentsui.files;
18d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
19df5add4169782b33779b4f21db263216bb37e9cfSteve McKayimport static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
207ef09a28caedf708bfc23d4adb4cdd71094aa954Steve McKay
217295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKayimport android.app.ActivityManager.TaskDescription;
22d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport android.app.FragmentManager;
23d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport android.content.Intent;
24a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.content.Context;
25a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.graphics.drawable.AdaptiveIconDrawable;
267295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKayimport android.graphics.drawable.BitmapDrawable;
27a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.graphics.drawable.Drawable;
28a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.graphics.Bitmap;
29a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.graphics.Canvas;
30a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.graphics.Color;
31a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Songimport android.graphics.Paint;
32d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport android.net.Uri;
33d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport android.os.Bundle;
34aa66c43df01033ccb957bfd1d513945676866f4cBen Linimport android.support.annotation.CallSuper;
350599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKayimport android.view.KeyEvent;
36a86732316c8fe1694f4c1702cdd6c8e0faff4e18Ben Linimport android.view.KeyboardShortcutGroup;
37d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport android.view.Menu;
38d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport android.view.MenuItem;
39d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
40bd9f05aa36bf19d8b34d0d73a59e9bd65d3d26ebSteve McKayimport com.android.documentsui.ActionModeController;
4116e0c1fcf2be1ac7daafa6cb2c1c97d751ca3e66Steve McKayimport com.android.documentsui.BaseActivity;
4216e0c1fcf2be1ac7daafa6cb2c1c97d751ca3e66Steve McKayimport com.android.documentsui.DocumentsApplication;
4375b7b9039cf0efcb188e916c6f510328bfe099a8Ben Linimport com.android.documentsui.FocusManager;
4492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKayimport com.android.documentsui.Injector;
457c35b036cb0de801a093df62da92c4a94399c26cBen Linimport com.android.documentsui.MenuManager.DirectoryDetails;
4616e0c1fcf2be1ac7daafa6cb2c1c97d751ca3e66Steve McKayimport com.android.documentsui.OperationDialogFragment;
47df5add4169782b33779b4f21db263216bb37e9cfSteve McKayimport com.android.documentsui.OperationDialogFragment.DialogType;
48239ab9779a40698da0fa6cff94575f5348f610a4Garfield Tanimport com.android.documentsui.ProviderExecutor;
49239ab9779a40698da0fa6cff94575f5348f610a4Garfield Tanimport com.android.documentsui.R;
50047182631669608af946480c2545a10acb2ef1bfSteve McKayimport com.android.documentsui.SharedInputHandler;
51052985f2e9687f4d62c173edeb2f0e5524082a7cSteve McKayimport com.android.documentsui.ShortcutsUpdater;
52d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.base.DocumentInfo;
5398f8c5f502e049a6b85439d773949cdbaa0f78aeSteve McKayimport com.android.documentsui.base.Features;
54d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.base.RootInfo;
55d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.base.State;
569666ce691a4d45344460f17cec3577dbe075235aGarfield, Tanimport com.android.documentsui.clipping.DocumentClipper;
57988d8a354b00dce7e24deee187c08a4591956ac9Steve McKayimport com.android.documentsui.dirlist.AnimationView.AnimationType;
58f68210e9a1e36e65e56e0c95cfe990f0145ea63fSteve McKayimport com.android.documentsui.dirlist.DirectoryFragment;
5930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.prefs.ScopedPreferences;
604f78ba643270b9d84da1952d8e408220b25ec6fdSteve McKayimport com.android.documentsui.selection.SelectionManager;
61c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport com.android.documentsui.services.FileOperationService;
62d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.sidebar.RootsFragment;
63c8889af6757ecb348fb8fd6dadf84d67d3478cbfSteve McKayimport com.android.documentsui.ui.DialogController;
6492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKayimport com.android.documentsui.ui.MessageBuilder;
65d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
66332d819d21dc4a719c67f6e2f8b1538bc30068b8Tomasz Mikolajewskiimport java.util.ArrayList;
67d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKayimport java.util.List;
68d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
69b68dd223b2623c22793f5dcd0f658de0aa92f80dSteve McKay/**
7064ac2519dc455a99cd1ac496cbf5cd76287dcce5Steve McKay * Standalone file management activity.
71b68dd223b2623c22793f5dcd0f658de0aa92f80dSteve McKay */
7292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKaypublic class FilesActivity extends BaseActivity implements ActionHandler.Addons {
73edc65bb47e1493eb12bb86c10fe706098a955658Steve McKay
746525a19f46eca7fbec21a71f833436823de03da3Steve McKay    private static final String TAG = "FilesActivity";
7592ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay    static final String PREFERENCES_SCOPE = "files";
76d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
7792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay    private Injector<ActionHandler<FilesActivity>> mInjector;
7879ae3a7d0e6dd6d2e953709a092e83002941d48fBen Lin    private ActivityInputHandler mActivityInputHandler;
79047182631669608af946480c2545a10acb2ef1bfSteve McKay    private SharedInputHandler mSharedInputHandler;
80b68dd223b2623c22793f5dcd0f658de0aa92f80dSteve McKay
81b6006b2ef723fdbb3fef3b4a350c8d363b127d0fSteve McKay    public FilesActivity() {
820fbfc653868966da7fd6109b247974e0d87a2297Steve McKay        super(R.layout.files_activity, TAG);
83b68dd223b2623c22793f5dcd0f658de0aa92f80dSteve McKay    }
84d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
85e3830da96f7358c2b791d1b8573837f4110844b8Tobias Thierer    // make these methods visible in this package to work around compiler bug http://b/62218600
86e3830da96f7358c2b791d1b8573837f4110844b8Tobias Thierer    @Override protected boolean focusSidebar() { return super.focusSidebar(); }
87e3830da96f7358c2b791d1b8573837f4110844b8Tobias Thierer    @Override protected boolean popDir() { return super.popDir(); }
88e3830da96f7358c2b791d1b8573837f4110844b8Tobias Thierer
89d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
90d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    public void onCreate(Bundle icicle) {
916525a19f46eca7fbec21a71f833436823de03da3Steve McKay
9292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        MessageBuilder messages = new MessageBuilder(this);
935bd5cb44eacc10fe7cec7c159d6f47d127a3195bSteve McKay        Features features = Features.create(this);
940ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay        ScopedPreferences prefs = ScopedPreferences.create(this, PREFERENCES_SCOPE);
950ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay
9692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector = new Injector<>(
970d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski                features,
9892ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                new Config(),
9992ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                ScopedPreferences.create(this, PREFERENCES_SCOPE),
10092ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                messages,
101b47b4b560c46336a0e6ba3e86db3f2d76b4b2bc3Garfield Tan                DialogController.create(features, this, messages),
1020ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay                DocumentsApplication.getFileTypeLookup(this),
1030ce04b7a3f2c76452f855d082cd57d5e4cab9d69Steve McKay                new ShortcutsUpdater(this, prefs)::update);
1046525a19f46eca7fbec21a71f833436823de03da3Steve McKay
105d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        super.onCreate(icicle);
106d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
10792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        DocumentClipper clipper = DocumentsApplication.getDocumentClipper(this);
10892ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.selectionMgr = new SelectionManager(SelectionManager.MODE_MULTIPLE);
109047182631669608af946480c2545a10acb2ef1bfSteve McKay
11092ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.focusManager = new FocusManager(
11198f8c5f502e049a6b85439d773949cdbaa0f78aeSteve McKay                mInjector.features,
112340ab17f468789bb507daeae116cf7940ba84b03Ben Lin                mInjector.selectionMgr,
113340ab17f468789bb507daeae116cf7940ba84b03Ben Lin                mDrawer,
114340ab17f468789bb507daeae116cf7940ba84b03Ben Lin                this::focusSidebar,
115340ab17f468789bb507daeae116cf7940ba84b03Ben Lin                getColor(R.color.accent_dark));
116047182631669608af946480c2545a10acb2ef1bfSteve McKay
11792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.menuManager = new MenuManager(
118710248d5ee766765b86fa36fe2ddd8d65f926755Steve McKay                mInjector.features,
119e5d6ca2c7a32c826607d826bdc18f90ca8e8b7daSteve McKay                mSearchManager,
120e5d6ca2c7a32c826607d826bdc18f90ca8e8b7daSteve McKay                mState,
121e5d6ca2c7a32c826607d826bdc18f90ca8e8b7daSteve McKay                new DirectoryDetails(this) {
122e5d6ca2c7a32c826607d826bdc18f90ca8e8b7daSteve McKay                    @Override
123e5d6ca2c7a32c826607d826bdc18f90ca8e8b7daSteve McKay                    public boolean hasItemsToPaste() {
12492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                        return clipper.hasItemsToPaste();
125e5d6ca2c7a32c826607d826bdc18f90ca8e8b7daSteve McKay                    }
126253a99248f1f3d50cd357d902bfc52e7b9367446Jon Mann                },
127253a99248f1f3d50cd357d902bfc52e7b9367446Jon Mann                getApplicationContext(),
128253a99248f1f3d50cd357d902bfc52e7b9367446Jon Mann                mInjector.selectionMgr,
1299bd4099ee27f8302a06fc66980079f29127318f8Jon Mann                mProviders::getApplicationName,
130253a99248f1f3d50cd357d902bfc52e7b9367446Jon Mann                mInjector.getModel()::getItemUri);
131bd9f05aa36bf19d8b34d0d73a59e9bd65d3d26ebSteve McKay
13292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.actionModeController = new ActionModeController(
133bd9f05aa36bf19d8b34d0d73a59e9bd65d3d26ebSteve McKay                this,
13492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.selectionMgr,
13592ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.menuManager,
13692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.messages);
137bd9f05aa36bf19d8b34d0d73a59e9bd65d3d26ebSteve McKay
13892ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.actions = new ActionHandler<>(
139c8889af6757ecb348fb8fd6dadf84d67d3478cbfSteve McKay                this,
140c8889af6757ecb348fb8fd6dadf84d67d3478cbfSteve McKay                mState,
1419bd4099ee27f8302a06fc66980079f29127318f8Jon Mann                mProviders,
14263bf8135243605949a3bb140167ef91f5c6ae2aeGarfield Tan                mDocs,
14363bf8135243605949a3bb140167ef91f5c6ae2aeGarfield Tan                mSearchManager,
144988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay                ProviderExecutor::forAuthority,
14592ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.actionModeController,
14692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                clipper,
14730d8c7988e15336d995e4b5033ba533a8333446fJon Mann                DocumentsApplication.getClipStore(this),
148da2c0f0b075ad9f770182e706c2ec158989568a7Garfield Tan                DocumentsApplication.getDragAndDropManager(this),
14930d8c7988e15336d995e4b5033ba533a8333446fJon Mann                mInjector);
1501f199483b77166242c4648270eed601748eef1efSteve McKay
151e967033315ed64bca8c89d601d187fd12754f1fbGarfield Tan        mInjector.searchManager = mSearchManager;
152e967033315ed64bca8c89d601d187fd12754f1fbGarfield Tan
15392ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mActivityInputHandler =
15492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                new ActivityInputHandler(mInjector.actions::deleteSelectedDocuments);
15598f8c5f502e049a6b85439d773949cdbaa0f78aeSteve McKay        mSharedInputHandler =
1560902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                new SharedInputHandler(
1570902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        mInjector.focusManager,
1580902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        mInjector.selectionMgr,
1590902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        mInjector.searchManager::cancelSearch,
1600902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        this::popDir,
1610902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        mInjector.features);
16279ae3a7d0e6dd6d2e953709a092e83002941d48fBen Lin
1637d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan        RootsFragment.show(getFragmentManager(), null);
164459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay
165cdbbbe05a66f70809669cb4f18ed7c42edb18426Tomasz Mikolajewski        final Intent intent = getIntent();
166739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay
16792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.actions.initLocation(intent);
1687295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay
1697295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        // Allow the activity to masquerade as another, so we can look both like
1707295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        // Downloads and Files, but with only a single underlying activity.
1717295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        if (intent.hasExtra(LauncherActivity.TASK_LABEL_RES)
1727295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay                && intent.hasExtra(LauncherActivity.TASK_ICON_RES)) {
1737295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay            updateTaskDescription(intent);
1747295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        }
1757295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay
176988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay        presentFileErrors(icicle, intent);
177988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay    }
178cdbbbe05a66f70809669cb4f18ed7c42edb18426Tomasz Mikolajewski
1797295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // This is called in the intent contains label and icon resources.
1807295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // When that is true, the launcher activity has supplied them so we
1817295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // can adapt our presentation to how we were launched.
1827295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // Without this code, overlaying launcher_icon and launcher_label
1837295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // resources won't create a complete illusion of the activity being renamed.
1847295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // E.g. if we re-brand Files to Downloads by overlaying label and icon
1857295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // when the user tapped recents they'd see not "Downloads", but the
1867295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // underlying Activity description...Files.
1877295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // Alternate if we rename this activity, when launching other ways
1887295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // like when browsing files on a removable disk, the app would be
1897295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    // called Downloads, which is also not the desired behavior.
1907295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    private void updateTaskDescription(final Intent intent) {
1917295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        int labelRes = intent.getIntExtra(LauncherActivity.TASK_LABEL_RES, -1);
1927295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        assert(labelRes > -1);
1937295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        String label = getResources().getString(labelRes);
1947295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay
1957295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        int iconRes = intent.getIntExtra(LauncherActivity.TASK_ICON_RES, -1);
1967295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay        assert(iconRes > -1);
1977295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay
198a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        Drawable drawable = getResources().getDrawable(
1997295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay                iconRes,
2007295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay                null  // we don't care about theme, since the supplier should have handled that.
2017295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay                );
2027295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay
203a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        setTaskDescription(new TaskDescription(label, flattenDrawableToBitmap(drawable)));
204a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song    }
205a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
206a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song    // AdaptiveIconDrawable assumes that the consumer of the icon applies the shadow and
207a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song    // recents assume that the provider of the task description handles these. Hence,
208a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song    // we apply the shadow treatment same as Launcher3 implementation.
209a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song    private Bitmap flattenDrawableToBitmap(Drawable d) {
210a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        // Percent of actual icon size
211a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        float ICON_SIZE_BLUR_FACTOR = 0.5f/48;
212a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        // Percent of actual icon size
213a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        float ICON_SIZE_KEY_SHADOW_DELTA_FACTOR = 1f/48;
214a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        int KEY_SHADOW_ALPHA = 61;
215a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        int AMBIENT_SHADOW_ALPHA = 30;
216a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        if (d instanceof BitmapDrawable) {
217a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            return ((BitmapDrawable) d).getBitmap();
218a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        } else if (d instanceof AdaptiveIconDrawable) {
219a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            AdaptiveIconDrawable aid = (AdaptiveIconDrawable) d;
220a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            int iconSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
221a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            int shadowSize = Math.max(iconSize, aid.getIntrinsicHeight());
222a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            aid.setBounds(0, 0, shadowSize, shadowSize);
223a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
224a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            float blur = ICON_SIZE_BLUR_FACTOR * shadowSize;
225a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            float keyShadowDistance = ICON_SIZE_KEY_SHADOW_DELTA_FACTOR * shadowSize;
226a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
227a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            int bitmapSize = (int) (shadowSize + 2 * blur + keyShadowDistance);
228a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            Bitmap shadow = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
229a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
230a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            Canvas canvas = new Canvas(shadow);
231a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            canvas.translate(blur + keyShadowDistance / 2, blur);
232a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
233a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
234a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            paint.setColor(Color.TRANSPARENT);
235a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
236a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            // Draw ambient shadow
237a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            paint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24);
238a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            canvas.drawPath(aid.getIconMask(), paint);
239a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
240a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            // Draw key shadow
241a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            canvas.translate(0, keyShadowDistance);
242a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            paint.setShadowLayer(blur, 0, 0, KEY_SHADOW_ALPHA << 24);
243a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            canvas.drawPath(aid.getIconMask(), paint);
244a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
245a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            // Draw original drawable
246a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            aid.draw(canvas);
247a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song
248a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            canvas.setBitmap(null);
249a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song            return shadow;
250a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        }
251a62e5047cb708a47c8b23aeb2be0951540a1d6e6Hyunyoung Song        return null;
2527295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay    }
2537295c484bfdd62066f6b49e225d0bf8af2cae19eSteve McKay
254988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay    private void presentFileErrors(Bundle icicle, final Intent intent) {
255dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski        final @DialogType int dialogType = intent.getIntExtra(
256dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski                FileOperationService.EXTRA_DIALOG_TYPE, DIALOG_TYPE_UNKNOWN);
257cdbbbe05a66f70809669cb4f18ed7c42edb18426Tomasz Mikolajewski        // DialogFragment takes care of restoring the dialog on configuration change.
258cdbbbe05a66f70809669cb4f18ed7c42edb18426Tomasz Mikolajewski        // Only show it manually for the first time (icicle is null).
259dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski        if (icicle == null && dialogType != DIALOG_TYPE_UNKNOWN) {
260dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski            final int opType = intent.getIntExtra(
2614833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    FileOperationService.EXTRA_OPERATION_TYPE,
262dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski                    FileOperationService.OPERATION_COPY);
26399f1dc3da6defec0596864934bfe76adc96a1d62Steve McKay            final ArrayList<DocumentInfo> docList =
26499f1dc3da6defec0596864934bfe76adc96a1d62Steve McKay                    intent.getParcelableArrayListExtra(FileOperationService.EXTRA_FAILED_DOCS);
265664025e3eb9184817a1ebc21920c601466b907c1Tomasz Mikolajewski            final ArrayList<Uri> uriList =
26699f1dc3da6defec0596864934bfe76adc96a1d62Steve McKay                    intent.getParcelableArrayListExtra(FileOperationService.EXTRA_FAILED_URIS);
267dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski            OperationDialogFragment.show(
268cdbbbe05a66f70809669cb4f18ed7c42edb18426Tomasz Mikolajewski                    getFragmentManager(),
269dd2b31c758e8d694867af58a425180689d25ead1Tomasz Mikolajewski                    dialogType,
27099f1dc3da6defec0596864934bfe76adc96a1d62Steve McKay                    docList,
27199f1dc3da6defec0596864934bfe76adc96a1d62Steve McKay                    uriList,
272cdbbbe05a66f70809669cb4f18ed7c42edb18426Tomasz Mikolajewski                    mState.stack,
273c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay                    opType);
274d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        }
275d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    }
276d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
2770fbfc653868966da7fd6109b247974e0d87a2297Steve McKay    @Override
27816e0c1fcf2be1ac7daafa6cb2c1c97d751ca3e66Steve McKay    public void includeState(State state) {
279d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        final Intent intent = getIntent();
2800574b18a7a95b29fab3cdb9ced6e5b46e24030feBen Kwa
28178ade2b9111c69a3cb169024646577f38136bbf7Garfield Tan        // This is a remnant of old logic where we used to initialize accept MIME types in
2829bd4099ee27f8302a06fc66980079f29127318f8Jon Mann        // BaseActivity. ProvidersAccess still rely on this being correctly initialized so we still have
28378ade2b9111c69a3cb169024646577f38136bbf7Garfield Tan        // to initialize it in FilesActivity.
28478ade2b9111c69a3cb169024646577f38136bbf7Garfield Tan        state.initAcceptMimes(intent, "*/*");
285459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        state.action = State.ACTION_BROWSE;
2860574b18a7a95b29fab3cdb9ced6e5b46e24030feBen Kwa        state.allowMultiple = true;
28764ac2519dc455a99cd1ac496cbf5cd76287dcce5Steve McKay
288459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        // Options specific to the DocumentsActivity.
2890af8afd3309538dec784ed0c9c35b252a8213123Steve McKay        assert(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
290d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    }
291d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
292d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
293d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    protected void onPostCreate(Bundle savedInstanceState) {
294d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        super.onPostCreate(savedInstanceState);
295a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        // This check avoids a flicker from "Recents" to "Home".
296a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        // Only update action bar at this point if there is an active
2970930d4ca4b5161a22b0ddeca86c06533624ad610Dooper        // search. Why? Because this avoid an early (undesired) load of
298a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        // the recents root...which is the default root in other activities.
299a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        // In Files app "Home" is the default, but it is loaded async.
30018d01e8d21376475cc9882dfcdce4a3d75f66690Steve McKay        // update will be called once Home root is loaded.
301a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        // Except while searching we need this call to ensure the
3020930d4ca4b5161a22b0ddeca86c06533624ad610Dooper        // search bits get laid out correctly.
303a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        if (mSearchManager.isSearching()) {
30418d01e8d21376475cc9882dfcdce4a3d75f66690Steve McKay            mNavigator.update();
305a8fa58d7449c0dd30e9701e611ae83175f2ad2f9Steve McKay        }
306d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    }
307d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
308d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
309459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay    public void onResume() {
310459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        super.onResume();
311459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay
312459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        final RootInfo root = getCurrentRoot();
313459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay
314459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        // If we're browsing a specific root, and that root went away, then we
315459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        // have no reason to hang around.
316459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        // TODO: Rather than just disappearing, maybe we should inform
317459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        // the user what has happened, let them close us. Less surprising.
3189bd4099ee27f8302a06fc66980079f29127318f8Jon Mann        if (mProviders.getRootBlocking(root.authority, root.rootId) == null) {
319459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay            finish();
320459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay        }
321459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay    }
322459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay
323459bc2b19ae24e3ad09b2945f21c8397177d5720Steve McKay    @Override
32418d01e8d21376475cc9882dfcdce4a3d75f66690Steve McKay    public String getDrawerTitle() {
32517f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay        Intent intent = getIntent();
32617f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay        return (intent != null && intent.hasExtra(Intent.EXTRA_TITLE))
32717f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKay                ? intent.getStringExtra(Intent.EXTRA_TITLE)
328a0b52655668ccbe3f12ca13ced4b34118a483783Steve McKay                : getString(R.string.app_label);
329d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    }
330d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
331d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
332d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    public boolean onPrepareOptionsMenu(Menu menu) {
333e980927578d51373a53a3aa9531bc73fb773fff8Steve McKay        super.onPrepareOptionsMenu(menu);
33492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.menuManager.updateOptionMenu(menu);
335e980927578d51373a53a3aa9531bc73fb773fff8Steve McKay        return true;
336d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    }
337d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
338d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
3391f199483b77166242c4648270eed601748eef1efSteve McKay    public boolean onOptionsItemSelected(MenuItem item) {
34049be24c91d71d8f6fe6cb8eb6837b46468abffb5Jon Mann        DirectoryFragment dir;
341f2c8b0dfe61deeedbed70931e0997a0b2f4eff45Steve McKay        switch (item.getItemId()) {
342ff7f3aeec1b4fc7e0b8ddb0e8b6b6e105140f68eBen Lin            case R.id.option_menu_create_dir:
3430af8afd3309538dec784ed0c9c35b252a8213123Steve McKay                assert(canCreateDirectory());
344ff7f3aeec1b4fc7e0b8ddb0e8b6b6e105140f68eBen Lin                mInjector.actions.showCreateDirectoryDialog();
3454972d71090b4e98951102ddd37fad95052525786Aga Wronska                break;
346ff7f3aeec1b4fc7e0b8ddb0e8b6b6e105140f68eBen Lin            case R.id.option_menu_new_window:
34792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.actions.openInNewWindow(mState.stack);
3484972d71090b4e98951102ddd37fad95052525786Aga Wronska                break;
349ff7f3aeec1b4fc7e0b8ddb0e8b6b6e105140f68eBen Lin            case R.id.option_menu_settings:
35092ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.actions.openSettings(getCurrentRoot());
3515668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin                break;
352ff7f3aeec1b4fc7e0b8ddb0e8b6b6e105140f68eBen Lin            case R.id.option_menu_select_all:
35330d8c7988e15336d995e4b5033ba533a8333446fJon Mann                mInjector.actions.selectAllFiles();
35449be24c91d71d8f6fe6cb8eb6837b46468abffb5Jon Mann                break;
3554972d71090b4e98951102ddd37fad95052525786Aga Wronska            default:
3564972d71090b4e98951102ddd37fad95052525786Aga Wronska                return super.onOptionsItemSelected(item);
3571f199483b77166242c4648270eed601748eef1efSteve McKay        }
3584972d71090b4e98951102ddd37fad95052525786Aga Wronska        return true;
3591f199483b77166242c4648270eed601748eef1efSteve McKay    }
3601f199483b77166242c4648270eed601748eef1efSteve McKay
3611f199483b77166242c4648270eed601748eef1efSteve McKay    @Override
362a86732316c8fe1694f4c1702cdd6c8e0faff4e18Ben Lin    public void onProvideKeyboardShortcuts(
363a86732316c8fe1694f4c1702cdd6c8e0faff4e18Ben Lin            List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
36492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.menuManager.updateKeyboardShortcutsMenu(data, this::getString);
365a86732316c8fe1694f4c1702cdd6c8e0faff4e18Ben Lin    }
366a86732316c8fe1694f4c1702cdd6c8e0faff4e18Ben Lin
367a86732316c8fe1694f4c1702cdd6c8e0faff4e18Ben Lin    @Override
368988d8a354b00dce7e24deee187c08a4591956ac9Steve McKay    public void refreshDirectory(@AnimationType int anim) {
369d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        final FragmentManager fm = getFragmentManager();
370d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        final RootInfo root = getCurrentRoot();
371d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        final DocumentInfo cwd = getCurrentDirectory();
372d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
3730af8afd3309538dec784ed0c9c35b252a8213123Steve McKay        assert(!mSearchManager.isSearching());
374af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska
375e967033315ed64bca8c89d601d187fd12754f1fbGarfield Tan        if (mState.stack.isRecents()) {
376d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay            DirectoryFragment.showRecentsOpen(fm, anim);
377d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        } else {
378af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska            // Normal boring directory
379af5ace5d5e3a273b151e012206efd029c2872b59Aga Wronska            DirectoryFragment.showDirectory(fm, root, cwd, anim);
380d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay        }
381d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    }
382d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay
383d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
384351a749751bc501c9d7c0f03ee5b542f0e7a7d7cSteve McKay    public void onDocumentsPicked(List<DocumentInfo> docs) {
385351a749751bc501c9d7c0f03ee5b542f0e7a7d7cSteve McKay        throw new UnsupportedOperationException();
386351a749751bc501c9d7c0f03ee5b542f0e7a7d7cSteve McKay    }
387351a749751bc501c9d7c0f03ee5b542f0e7a7d7cSteve McKay
388351a749751bc501c9d7c0f03ee5b542f0e7a7d7cSteve McKay    @Override
389eed2f4ec78227b5e173ff667a5517637a91b9a30Steve McKay    public void onDocumentPicked(DocumentInfo doc) {
390d22cc1852ed3e028a37d713e41c57286d2e4c9f2Tomasz Mikolajewski        throw new UnsupportedOperationException();
391be4e38b3113224d59cb1a2d4a8d29324019afb00Tomasz Mikolajewski    }
392be4e38b3113224d59cb1a2d4a8d29324019afb00Tomasz Mikolajewski
393804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan    @Override
39416e0c1fcf2be1ac7daafa6cb2c1c97d751ca3e66Steve McKay    public void onDirectoryCreated(DocumentInfo doc) {
39581afd7f587176e7d63f00d533b1258dfec84bf5cBen Lin        assert(doc.isDirectory());
39692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        mInjector.focusManager.focusDocument(doc.documentId);
39781afd7f587176e7d63f00d533b1258dfec84bf5cBen Lin    }
39881afd7f587176e7d63f00d533b1258dfec84bf5cBen Lin
399aa66c43df01033ccb957bfd1d513945676866f4cBen Lin    @CallSuper
400aa66c43df01033ccb957bfd1d513945676866f4cBen Lin    @Override
401aa66c43df01033ccb957bfd1d513945676866f4cBen Lin    public boolean onKeyDown(int keyCode, KeyEvent event) {
402047182631669608af946480c2545a10acb2ef1bfSteve McKay        return mActivityInputHandler.onKeyDown(keyCode, event)
4030902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                || mSharedInputHandler.onKeyDown(
4040902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        keyCode,
4050902f07dec9cfb0bd5d7c9c6222b433b91bf2051Ben Lin                        event)
406047182631669608af946480c2545a10acb2ef1bfSteve McKay                || super.onKeyDown(keyCode, event);
407aa66c43df01033ccb957bfd1d513945676866f4cBen Lin    }
408aa66c43df01033ccb957bfd1d513945676866f4cBen Lin
409d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay    @Override
4100599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
4110599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay        DirectoryFragment dir;
412d4800817c434cb77ab03a2fd061da897a05cb933Steve McKay        // TODO: All key events should be statically bound using alphabeticShortcut.
413d4800817c434cb77ab03a2fd061da897a05cb933Steve McKay        // But not working.
4140599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay        switch (keyCode) {
4150599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay            case KeyEvent.KEYCODE_A:
41630d8c7988e15336d995e4b5033ba533a8333446fJon Mann                mInjector.actions.selectAllFiles();
4170599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay                return true;
418ff4d5846f8de51d51b87116cd07e559d75de2642Ben Lin            case KeyEvent.KEYCODE_X:
41992ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.actions.cutToClipboard();
420ff4d5846f8de51d51b87116cd07e559d75de2642Ben Lin                return true;
4211f199483b77166242c4648270eed601748eef1efSteve McKay            case KeyEvent.KEYCODE_C:
42292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay                mInjector.actions.copyToClipboard();
4236035b3cc3b6b298ff8065b2ed55da651e6950802Steve McKay                return true;
4246035b3cc3b6b298ff8065b2ed55da651e6950802Steve McKay            case KeyEvent.KEYCODE_V:
425d4800817c434cb77ab03a2fd061da897a05cb933Steve McKay                dir = getDirectoryFragment();
426d4800817c434cb77ab03a2fd061da897a05cb933Steve McKay                if (dir != null) {
427d4800817c434cb77ab03a2fd061da897a05cb933Steve McKay                    dir.pasteFromClipboard();
428d4800817c434cb77ab03a2fd061da897a05cb933Steve McKay                }
4296035b3cc3b6b298ff8065b2ed55da651e6950802Steve McKay                return true;
4306035b3cc3b6b298ff8065b2ed55da651e6950802Steve McKay            default:
4316035b3cc3b6b298ff8065b2ed55da651e6950802Steve McKay                return super.onKeyShortcut(keyCode, event);
4320599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay        }
4330599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay    }
4340599a443b9bb4fd2ff8c6c6b95f94ba8f6ed3c9bSteve McKay
435b68dd223b2623c22793f5dcd0f658de0aa92f80dSteve McKay    @Override
43692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay    public Injector<ActionHandler<FilesActivity>> getInjector() {
43792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay        return mInjector;
438c8889af6757ecb348fb8fd6dadf84d67d3478cbfSteve McKay    }
439d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay}
440