1 /* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.mail.browse; 19 20 import android.content.Context; 21 import android.graphics.drawable.Drawable; 22 import android.net.Uri; 23 import android.os.Bundle; 24 import android.util.AttributeSet; 25 import android.view.View; 26 import android.widget.Button; 27 import android.widget.LinearLayout; 28 import android.widget.TextView; 29 30 import com.android.mail.R; 31 import com.android.mail.providers.Folder; 32 import com.android.mail.providers.UIProvider; 33 import com.android.mail.ui.ViewMode; 34 import com.android.mail.utils.Utils; 35 36 public final class ConversationListFooterView extends LinearLayout implements View.OnClickListener, 37 ViewMode.ModeChangeListener { 38 39 public interface FooterViewClickListener { 40 void onFooterViewErrorActionClick(Folder folder, int errorStatus); 41 void onFooterViewLoadMoreClick(Folder folder); 42 } 43 44 private View mLoading; 45 private View mNetworkError; 46 private View mLoadMore; 47 private Button mErrorActionButton; 48 private TextView mErrorText; 49 private Folder mFolder; 50 private Uri mLoadMoreUri; 51 private int mErrorStatus; 52 private FooterViewClickListener mClickListener; 53 private final boolean mTabletDevice; 54 // Backgrounds for different states. 55 private static Drawable sWideBackground; 56 private static Drawable sNormalBackground; 57 58 public ConversationListFooterView(Context context, AttributeSet attrs) { 59 super(context, attrs); 60 mTabletDevice = Utils.useTabletUI(context.getResources()); 61 } 62 63 @Override 64 protected void onFinishInflate() { 65 super.onFinishInflate(); 66 67 mLoading = findViewById(R.id.loading); 68 mNetworkError = findViewById(R.id.network_error); 69 mLoadMore = findViewById(R.id.load_more); 70 mLoadMore.setOnClickListener(this); 71 mErrorActionButton = (Button) findViewById(R.id.error_action_button); 72 mErrorActionButton.setOnClickListener(this); 73 mErrorText = (TextView)findViewById(R.id.error_text); 74 } 75 76 public void setClickListener(FooterViewClickListener listener) { 77 mClickListener = listener; 78 } 79 80 @Override 81 public void onClick(View v) { 82 final int id = v.getId(); 83 final Folder f = (Folder) v.getTag(); 84 if (id == R.id.error_action_button) { 85 mClickListener.onFooterViewErrorActionClick(f, mErrorStatus); 86 } else if (id == R.id.load_more) { 87 mClickListener.onFooterViewLoadMoreClick(f); 88 } 89 } 90 91 public void setFolder(Folder folder) { 92 mFolder = folder; 93 mErrorActionButton.setTag(mFolder); 94 mLoadMore.setTag(mFolder); 95 mLoadMoreUri = folder.loadMoreUri; 96 } 97 98 /** 99 * Update the view to reflect the new folder status. 100 */ 101 public boolean updateStatus(final ConversationCursor cursor) { 102 if (cursor == null) { 103 mLoading.setVisibility(View.GONE); 104 mNetworkError.setVisibility(View.GONE); 105 mLoadMore.setVisibility(View.GONE); 106 return false; 107 } 108 boolean showFooter = true; 109 final Bundle extras = cursor.getExtras(); 110 final int cursorStatus = extras.getInt(UIProvider.CursorExtraKeys.EXTRA_STATUS); 111 mErrorStatus = extras.containsKey(UIProvider.CursorExtraKeys.EXTRA_ERROR) ? 112 extras.getInt(UIProvider.CursorExtraKeys.EXTRA_ERROR) 113 : UIProvider.LastSyncResult.SUCCESS; 114 final int totalCount = extras.getInt(UIProvider.CursorExtraKeys.EXTRA_TOTAL_COUNT); 115 116 if (UIProvider.CursorStatus.isWaitingForResults(cursorStatus)) { 117 if (cursor.getCount() != 0) { 118 // When loading more, show the spinner in the footer. 119 mLoading.setVisibility(View.VISIBLE); 120 mNetworkError.setVisibility(View.GONE); 121 mLoadMore.setVisibility(View.GONE); 122 } else { 123 // We're currently loading, but we have no messages at all. We don't need to show 124 // the footer, because we should be displaying the loading state on the 125 // conversation list itself. 126 showFooter = false; 127 } 128 } else if (mErrorStatus != UIProvider.LastSyncResult.SUCCESS) { 129 // We are in some error state, show the footer with an error message. 130 mNetworkError.setVisibility(View.VISIBLE); 131 mErrorText.setText(Utils.getSyncStatusText(getContext(), mErrorStatus)); 132 mLoading.setVisibility(View.GONE); 133 mLoadMore.setVisibility(View.GONE); 134 // Only show the "Retry" button for I/O errors; it won't help for 135 // internal errors. 136 mErrorActionButton.setVisibility( 137 mErrorStatus != UIProvider.LastSyncResult.SECURITY_ERROR ? 138 View.VISIBLE : View.GONE); 139 140 final int actionTextResourceId; 141 switch (mErrorStatus) { 142 case UIProvider.LastSyncResult.CONNECTION_ERROR: 143 actionTextResourceId = R.string.retry; 144 break; 145 case UIProvider.LastSyncResult.SERVER_ERROR: 146 actionTextResourceId = R.string.retry; 147 break; 148 case UIProvider.LastSyncResult.AUTH_ERROR: 149 actionTextResourceId = R.string.signin; 150 break; 151 case UIProvider.LastSyncResult.SECURITY_ERROR: 152 actionTextResourceId = R.string.retry; 153 mNetworkError.setVisibility(View.GONE); 154 break; // Currently we do nothing for security errors. 155 case UIProvider.LastSyncResult.STORAGE_ERROR: 156 actionTextResourceId = R.string.info; 157 break; 158 case UIProvider.LastSyncResult.INTERNAL_ERROR: 159 actionTextResourceId = R.string.report; 160 break; 161 default: 162 actionTextResourceId = R.string.retry; 163 mNetworkError.setVisibility(View.GONE); 164 break; 165 } 166 mErrorActionButton.setText(actionTextResourceId); 167 168 } else if (mLoadMoreUri != null && cursor.getCount() < totalCount) { 169 // We know that there are more messages on the server than we have locally, so we 170 // need to show the footer with the "load more" button. 171 mLoading.setVisibility(View.GONE); 172 mNetworkError.setVisibility(View.GONE); 173 mLoadMore.setVisibility(View.VISIBLE); 174 } else { 175 showFooter = false; 176 } 177 return showFooter; 178 } 179 180 /** 181 * Update to the appropriate background when the view mode changes. 182 */ 183 @Override 184 public void onViewModeChanged(int newMode) { 185 final Drawable drawable; 186 if (mTabletDevice && newMode == ViewMode.CONVERSATION_LIST) { 187 drawable = getWideBackground(); 188 } else { 189 drawable = getNormalBackground(); 190 } 191 setBackgroundDrawable(drawable); 192 } 193 194 private Drawable getWideBackground() { 195 if (sWideBackground == null) { 196 sWideBackground = getBackground(R.drawable.conversation_wide_unread_selector); 197 } 198 return sWideBackground; 199 } 200 201 private Drawable getNormalBackground() { 202 if (sNormalBackground == null) { 203 sNormalBackground = getBackground(R.drawable.conversation_item_background_selector); 204 } 205 return sNormalBackground; 206 } 207 208 private Drawable getBackground(int resId) { 209 return getContext().getResources().getDrawable(resId); 210 } 211 } 212