17b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin/*
27b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * Copyright (C) 2016 The Android Open Source Project
37b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin *
47b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * Licensed under the Apache License, Version 2.0 (the "License");
57b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * you may not use this file except in compliance with the License.
67b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * You may obtain a copy of the License at
77b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin *
87b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin *      http://www.apache.org/licenses/LICENSE-2.0
97b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin *
107b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * Unless required by applicable law or agreed to in writing, software
117b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * distributed under the License is distributed on an "AS IS" BASIS,
127b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * See the License for the specific language governing permissions and
147b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * limitations under the License.
157b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin */
167b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
177b38f3465c3779384a17e84cc04609d9d68b56f4Ben Linpackage com.android.documentsui.dirlist;
187b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
197b38f3465c3779384a17e84cc04609d9d68b56f4Ben Linimport android.annotation.Nullable;
20339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Linimport android.app.AuthenticationRequiredException;
21339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Linimport android.app.PendingIntent;
22f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Linimport android.graphics.drawable.Drawable;
23339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Linimport android.util.Log;
247b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
25befdcc94a59e05d05971b28ddd47aa0a7601063aBen Linimport com.android.documentsui.DocumentsApplication;
26339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Linimport com.android.documentsui.Model.Update;
277b38f3465c3779384a17e84cc04609d9d68b56f4Ben Linimport com.android.documentsui.R;
28f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Linimport com.android.documentsui.base.RootInfo;
29e77419c6b4aecf4eb71b49898d6b63034a0771e4Ben Linimport com.android.documentsui.base.Shared;
307b38f3465c3779384a17e84cc04609d9d68b56f4Ben Linimport com.android.documentsui.dirlist.DocumentsAdapter.Environment;
317b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
327b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin/**
337b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin * Data object used by {@link InflateMessageDocumentHolder} and {@link HeaderMessageDocumentHolder}.
347b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin */
35f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin
367b38f3465c3779384a17e84cc04609d9d68b56f4Ben Linabstract class Message {
377b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    protected final Environment mEnv;
38f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    // If the message has a button, this will be the default button call back.
39f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    protected final Runnable mDefaultCallback;
40f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    // If a message has a new callback when updated, this field should be updated.
41f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    protected @Nullable Runnable mCallback;
42f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin
437b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    private @Nullable CharSequence mMessageString;
44f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    private @Nullable CharSequence mButtonString;
45f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    private @Nullable Drawable mIcon;
467b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    private boolean mShouldShow = false;
477b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
48f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    Message(Environment env, Runnable defaultCallback) {
497b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        mEnv = env;
50f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        mDefaultCallback = defaultCallback;
517b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
527b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
537b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    abstract void update(Update Event);
547b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
55f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    protected void update(CharSequence messageString, CharSequence buttonString, Drawable icon) {
567b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        if (messageString == null) {
577b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            return;
587b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
597b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        mMessageString = messageString;
60f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        mButtonString = buttonString;
61f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        mIcon = icon;
627b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        mShouldShow = true;
637b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
647b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
657b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    void reset() {
667b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        mMessageString = null;
67f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        mIcon = null;
687b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        mShouldShow = false;
697b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
707b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
71f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    void runCallback() {
72f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        if (mCallback != null) {
73f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            mCallback.run();
74f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        } else {
75f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            mDefaultCallback.run();
76f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        }
77f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    }
78f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin
79f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    Drawable getIcon() {
80f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        return mIcon;
817b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
827b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
837b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    boolean shouldShow() {
847b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        return mShouldShow;
857b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
867b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
877b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    CharSequence getMessageString() {
887b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        return mMessageString;
897b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
907b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
91f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    CharSequence getButtonString() {
92f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        return mButtonString;
93f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin    }
94f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin
957b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    final static class HeaderMessage extends Message {
967b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
97339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Lin        private static final String TAG = "HeaderMessage";
98f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin
99f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        HeaderMessage(Environment env, Runnable callback) {
100f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            super(env, callback);
1017b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
1027b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
1037b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        @Override
1047b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        void update(Update event) {
1057b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            reset();
1067b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            // Error gets first dibs ... for now
1077b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            // TODO: These should be different Message objects getting updated instead of
1087b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            // overwriting.
109339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Lin            if (event.hasAuthenticationException()) {
110befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin                updateToAuthenticationExceptionHeader(event);
111f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            } else if (mEnv.getModel().error != null) {
112f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin                update(mEnv.getModel().error, null,
113f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin                        mEnv.getContext().getDrawable(R.drawable.ic_dialog_alert));
1147b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            } else if (mEnv.getModel().info != null) {
115f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin                update(mEnv.getModel().info, null,
116f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin                        mEnv.getContext().getDrawable(R.drawable.ic_dialog_info));
1177b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            }
1187b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
119f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin
120befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin        private void updateToAuthenticationExceptionHeader(Update event) {
12198f8c5f502e049a6b85439d773949cdbaa0f78aeSteve McKay            assert(mEnv.getFeatures().isRemoteActionsEnabled());
12298f8c5f502e049a6b85439d773949cdbaa0f78aeSteve McKay
123f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            RootInfo root = mEnv.getDisplayState().stack.getRoot();
124befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin            String appName = DocumentsApplication
125befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin                    .getProvidersCache(mEnv.getContext()).getApplicationName(root.authority);
126befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin            update(mEnv.getContext().getString(R.string.authentication_required, appName),
127befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin                    mEnv.getContext().getResources().getText(R.string.sign_in),
128f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin                    mEnv.getContext().getDrawable(R.drawable.ic_dialog_info));
129f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            mCallback = () -> {
130339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Lin                AuthenticationRequiredException exception =
131339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Lin                        (AuthenticationRequiredException) event.getException();
132800300826ebb50f5a26393bc966c27fa26e9a16fBen Lin                mEnv.getActionHandler().startAuthentication(exception.getUserAction());
133f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            };
134f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        }
1357b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
1367b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
1377b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    final static class InflateMessage extends Message {
1387b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
139f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin        InflateMessage(Environment env, Runnable callback) {
140f8f06e946bd8d3965b2ea96f83d5e46575193f05Ben Lin            super(env, callback);
1417b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
1427b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
1437b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        @Override
1447b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        void update(Update event) {
1457b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            reset();
146339968c3c0a47061afe0b3fc6b9ed0627f5b74c6Ben Lin            if (event.hasException() && !event.hasAuthenticationException()) {
14702350fec8f0e47bea279dcecfd75804c8f689215Garfield Tan                updateToInflatedErrorMesage();
148befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin            } else if (event.hasAuthenticationException()) {
149befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin                updateToCantDisplayContentMessage();
1507b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            } else if (mEnv.getModel().getModelIds().length == 0) {
1517b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin                updateToInflatedEmptyMessage();
1527b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            }
1537b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
1547b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
15502350fec8f0e47bea279dcecfd75804c8f689215Garfield Tan        private void updateToInflatedErrorMesage() {
15602350fec8f0e47bea279dcecfd75804c8f689215Garfield Tan            update(mEnv.getContext().getResources().getText(R.string.query_error), null,
15702350fec8f0e47bea279dcecfd75804c8f689215Garfield Tan                    mEnv.getContext().getDrawable(R.drawable.hourglass));
1587b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
1597b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin
160befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin        private void updateToCantDisplayContentMessage() {
161befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin            update(mEnv.getContext().getResources().getText(R.string.cant_display_content), null,
162fe39ef04eec497d171d54423a3d93e85f3162c22Amin Shaikh                    mEnv.getContext().getDrawable(R.drawable.empty));
163befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin        }
164befdcc94a59e05d05971b28ddd47aa0a7601063aBen Lin
1657b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        private void updateToInflatedEmptyMessage() {
1667b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            final CharSequence message;
1677b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            if (mEnv.isInSearchMode()) {
1687b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin                message = String.format(
1697b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin                        String.valueOf(
1707b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin                                mEnv.getContext().getResources().getText(R.string.no_results)),
1717b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin                        mEnv.getDisplayState().stack.getRoot().title);
1727b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            } else {
1737b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin                message = mEnv.getContext().getResources().getText(R.string.empty);
1747b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin            }
175fe39ef04eec497d171d54423a3d93e85f3162c22Amin Shaikh            update(message, null, mEnv.getContext().getDrawable(R.drawable.empty));
1767b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin        }
1777b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin    }
1787b38f3465c3779384a17e84cc04609d9d68b56f4Ben Lin}
179