1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.documentsui.dirlist;
18 
19 import android.annotation.Nullable;
20 import android.app.AuthenticationRequiredException;
21 import android.app.PendingIntent;
22 import android.graphics.drawable.Drawable;
23 import android.util.Log;
24 
25 import com.android.documentsui.DocumentsApplication;
26 import com.android.documentsui.Model.Update;
27 import com.android.documentsui.R;
28 import com.android.documentsui.base.RootInfo;
29 import com.android.documentsui.base.Shared;
30 import com.android.documentsui.dirlist.DocumentsAdapter.Environment;
31 
32 /**
33  * Data object used by {@link InflateMessageDocumentHolder} and {@link HeaderMessageDocumentHolder}.
34  */
35 
36 abstract class Message {
37     protected final Environment mEnv;
38     // If the message has a button, this will be the default button call back.
39     protected final Runnable mDefaultCallback;
40     // If a message has a new callback when updated, this field should be updated.
41     protected @Nullable Runnable mCallback;
42 
43     private @Nullable CharSequence mMessageString;
44     private @Nullable CharSequence mButtonString;
45     private @Nullable Drawable mIcon;
46     private boolean mShouldShow = false;
47 
Message(Environment env, Runnable defaultCallback)48     Message(Environment env, Runnable defaultCallback) {
49         mEnv = env;
50         mDefaultCallback = defaultCallback;
51     }
52 
update(Update Event)53     abstract void update(Update Event);
54 
update(CharSequence messageString, CharSequence buttonString, Drawable icon)55     protected void update(CharSequence messageString, CharSequence buttonString, Drawable icon) {
56         if (messageString == null) {
57             return;
58         }
59         mMessageString = messageString;
60         mButtonString = buttonString;
61         mIcon = icon;
62         mShouldShow = true;
63     }
64 
reset()65     void reset() {
66         mMessageString = null;
67         mIcon = null;
68         mShouldShow = false;
69     }
70 
runCallback()71     void runCallback() {
72         if (mCallback != null) {
73             mCallback.run();
74         } else {
75             mDefaultCallback.run();
76         }
77     }
78 
getIcon()79     Drawable getIcon() {
80         return mIcon;
81     }
82 
shouldShow()83     boolean shouldShow() {
84         return mShouldShow;
85     }
86 
getMessageString()87     CharSequence getMessageString() {
88         return mMessageString;
89     }
90 
getButtonString()91     CharSequence getButtonString() {
92         return mButtonString;
93     }
94 
95     final static class HeaderMessage extends Message {
96 
97         private static final String TAG = "HeaderMessage";
98 
HeaderMessage(Environment env, Runnable callback)99         HeaderMessage(Environment env, Runnable callback) {
100             super(env, callback);
101         }
102 
103         @Override
update(Update event)104         void update(Update event) {
105             reset();
106             // Error gets first dibs ... for now
107             // TODO: These should be different Message objects getting updated instead of
108             // overwriting.
109             if (event.hasAuthenticationException()) {
110                 updateToAuthenticationExceptionHeader(event);
111             } else if (mEnv.getModel().error != null) {
112                 update(mEnv.getModel().error, null,
113                         mEnv.getContext().getDrawable(R.drawable.ic_dialog_alert));
114             } else if (mEnv.getModel().info != null) {
115                 update(mEnv.getModel().info, null,
116                         mEnv.getContext().getDrawable(R.drawable.ic_dialog_info));
117             }
118         }
119 
updateToAuthenticationExceptionHeader(Update event)120         private void updateToAuthenticationExceptionHeader(Update event) {
121             assert(mEnv.getFeatures().isRemoteActionsEnabled());
122 
123             RootInfo root = mEnv.getDisplayState().stack.getRoot();
124             String appName = DocumentsApplication
125                     .getProvidersCache(mEnv.getContext()).getApplicationName(root.authority);
126             update(mEnv.getContext().getString(R.string.authentication_required, appName),
127                     mEnv.getContext().getResources().getText(R.string.sign_in),
128                     mEnv.getContext().getDrawable(R.drawable.ic_dialog_info));
129             mCallback = () -> {
130                 AuthenticationRequiredException exception =
131                         (AuthenticationRequiredException) event.getException();
132                 mEnv.getActionHandler().startAuthentication(exception.getUserAction());
133             };
134         }
135     }
136 
137     final static class InflateMessage extends Message {
138 
InflateMessage(Environment env, Runnable callback)139         InflateMessage(Environment env, Runnable callback) {
140             super(env, callback);
141         }
142 
143         @Override
update(Update event)144         void update(Update event) {
145             reset();
146             if (event.hasException() && !event.hasAuthenticationException()) {
147                 updateToInflatedErrorMesage(
148                         Shared.DEBUG ? Shared.getStackTrace(event.getException()) : null);
149             } else if (event.hasAuthenticationException()) {
150                 updateToCantDisplayContentMessage();
151             } else if (mEnv.getModel().getModelIds().length == 0) {
152                 updateToInflatedEmptyMessage();
153             }
154         }
155 
updateToInflatedErrorMesage(@ullable String debugString)156         private void updateToInflatedErrorMesage(@Nullable String debugString) {
157             if (debugString == null) {
158                 update(mEnv.getContext().getResources().getText(R.string.query_error), null,
159                         mEnv.getContext().getDrawable(R.drawable.hourglass));
160             } else {
161                 assert (Shared.DEBUG);
162                 update(debugString, null, mEnv.getContext().getDrawable(R.drawable.hourglass));
163             }
164         }
165 
updateToCantDisplayContentMessage()166         private void updateToCantDisplayContentMessage() {
167             update(mEnv.getContext().getResources().getText(R.string.cant_display_content), null,
168                     mEnv.getContext().getDrawable(R.drawable.cabinet));
169         }
170 
updateToInflatedEmptyMessage()171         private void updateToInflatedEmptyMessage() {
172             final CharSequence message;
173             if (mEnv.isInSearchMode()) {
174                 message = String.format(
175                         String.valueOf(
176                                 mEnv.getContext().getResources().getText(R.string.no_results)),
177                         mEnv.getDisplayState().stack.getRoot().title);
178             } else {
179                 message = mEnv.getContext().getResources().getText(R.string.empty);
180             }
181             update(message, null, mEnv.getContext().getDrawable(R.drawable.cabinet));
182         }
183     }
184 }
185