1 /* 2 * Copyright (C) 2020 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.car.carlauncher.homescreen; 18 19 import android.graphics.drawable.Drawable; 20 import android.os.Bundle; 21 import android.util.Size; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.view.ViewStub; 26 import android.widget.ImageButton; 27 import android.widget.ImageView; 28 import android.widget.TextView; 29 30 import androidx.fragment.app.Fragment; 31 32 import com.android.car.apps.common.CrossfadeImageView; 33 import com.android.car.carlauncher.R; 34 import com.android.car.carlauncher.homescreen.ui.CardContent; 35 import com.android.car.carlauncher.homescreen.ui.CardHeader; 36 import com.android.car.carlauncher.homescreen.ui.DescriptiveTextView; 37 import com.android.car.carlauncher.homescreen.ui.DescriptiveTextWithControlsView; 38 import com.android.car.carlauncher.homescreen.ui.TextBlockView; 39 40 /** 41 * Abstract class for a {@link Fragment} that implements the Home App's View interface. 42 * 43 * {@link HomeCardInterface.View} classes that extend HomeCardFragment will override the update 44 * methods of the types of CardContent that they support. Each CardContent class corresponds to a 45 * layout shown on the card. The layout is a combination of xml files. 46 * {@link DescriptiveTextWithControlsView}: card_content_descriptive_text, card_content_button_trio 47 * {@link DescriptiveTextView}: card_content_descriptive_text, card_content_tap_for_more_text 48 * {@link TextBlockView}: card_content_text_block, card_content_tap_for_more_text 49 */ 50 public class HomeCardFragment extends Fragment implements HomeCardInterface.View { 51 52 private static final String TAG = "HomeFragment"; 53 private HomeCardInterface.Presenter mPresenter; 54 private Size mSize; 55 private View mCardBackground; 56 private CrossfadeImageView mCardBackgroundImage; 57 private View mRootView; 58 private TextView mCardTitle; 59 private ImageView mCardIcon; 60 61 // Views from card_content_text_block.xml 62 private View mTextBlockLayoutView; 63 private TextView mTextBlock; 64 private TextView mTextBlockTapForMore; 65 66 // Views from card_content_descriptive_text_only.xml 67 private View mDescriptiveTextOnlyLayoutView; 68 private ImageView mDescriptiveTextOnlyOptionalImage; 69 private TextView mDescriptiveTextOnlyTitle; 70 private TextView mDescriptiveTextOnlySubtitle; 71 private TextView mDescriptiveTextOnlyTapForMore; 72 73 // Views from card_content_descriptive_text_with_controls.xml 74 private View mDescriptiveTextWithControlsLayoutView; 75 private ImageView mDescriptiveTextWithControlsOptionalImage; 76 private TextView mDescriptiveTextWithControlsTitle; 77 private TextView mDescriptiveTextWithControlsSubtitle; 78 private View mControlBarView; 79 private ImageButton mControlBarLeftButton; 80 private ImageButton mControlBarCenterButton; 81 private ImageButton mControlBarRightButton; 82 83 @Override setPresenter(HomeCardInterface.Presenter presenter)84 public void setPresenter(HomeCardInterface.Presenter presenter) { 85 mPresenter = presenter; 86 } 87 88 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)89 public View onCreateView(LayoutInflater inflater, ViewGroup container, 90 Bundle savedInstanceState) { 91 mRootView = inflater.inflate(R.layout.card_fragment, container, false); 92 mCardTitle = mRootView.findViewById(R.id.card_name); 93 mCardIcon = mRootView.findViewById(R.id.card_icon); 94 return mRootView; 95 } 96 97 @Override onViewCreated(View view, Bundle savedInstanceState)98 public void onViewCreated(View view, Bundle savedInstanceState) { 99 super.onViewCreated(view, savedInstanceState); 100 mPresenter.onViewCreated(); 101 mRootView.setOnClickListener(v -> mPresenter.onViewClicked(v)); 102 } 103 104 @Override onDestroy()105 public void onDestroy() { 106 super.onDestroy(); 107 if (mPresenter != null) { 108 mPresenter.onViewDestroyed(); 109 } 110 mSize = null; 111 } 112 113 @Override getFragment()114 public Fragment getFragment() { 115 return this; 116 } 117 118 /** 119 * Returns the size of the card or null if the view hasn't yet been laid out 120 */ getCardSize()121 protected Size getCardSize() { 122 if (mSize == null && mRootView.isLaidOut()) { 123 mSize = new Size(mRootView.getWidth(), mRootView.getHeight()); 124 } 125 return mSize; 126 } 127 128 /** 129 * Removes the audio card from view 130 */ 131 @Override hideCard()132 public void hideCard() { 133 hideAllViews(); 134 mRootView.setVisibility(View.GONE); 135 } 136 137 /** 138 * Updates the card's header: name and icon of source app 139 */ 140 @Override updateHeaderView(CardHeader header)141 public void updateHeaderView(CardHeader header) { 142 requireActivity().runOnUiThread(() -> { 143 mRootView.setVisibility(View.VISIBLE); 144 mCardTitle.setText(header.getCardTitle()); 145 mCardIcon.setImageDrawable(header.getCardIcon()); 146 }); 147 } 148 149 @Override updateContentView(CardContent content)150 public final void updateContentView(CardContent content) { 151 requireActivity().runOnUiThread(() -> { 152 hideAllViews(); 153 updateContentViewInternal(content); 154 }); 155 } 156 157 /** 158 * Child classes can override this method for updating their specific types of card content 159 */ updateContentViewInternal(CardContent content)160 protected void updateContentViewInternal(CardContent content) { 161 switch (content.getType()) { 162 case DESCRIPTIVE_TEXT: 163 DescriptiveTextView descriptiveTextContent = (DescriptiveTextView) content; 164 updateDescriptiveTextOnlyView(descriptiveTextContent.getTitle(), 165 descriptiveTextContent.getSubtitle(), descriptiveTextContent.getImage(), 166 descriptiveTextContent.getFooter()); 167 break; 168 case DESCRIPTIVE_TEXT_WITH_CONTROLS: 169 DescriptiveTextWithControlsView 170 descriptiveTextWithControlsContent = 171 (DescriptiveTextWithControlsView) content; 172 updateDescriptiveTextWithControlsView(descriptiveTextWithControlsContent.getTitle(), 173 descriptiveTextWithControlsContent.getSubtitle(), 174 descriptiveTextWithControlsContent.getImage(), 175 descriptiveTextWithControlsContent.getLeftControl(), 176 descriptiveTextWithControlsContent.getCenterControl(), 177 descriptiveTextWithControlsContent.getRightControl()); 178 break; 179 case TEXT_BLOCK: 180 TextBlockView textBlockContent = (TextBlockView) content; 181 updateTextBlock(textBlockContent.getText(), textBlockContent.getFooter()); 182 break; 183 } 184 } 185 updateDescriptiveTextOnlyView(CharSequence primaryText, CharSequence secondaryText, Drawable optionalImage, CharSequence tapForMoreText)186 protected final void updateDescriptiveTextOnlyView(CharSequence primaryText, 187 CharSequence secondaryText, Drawable optionalImage, CharSequence tapForMoreText) { 188 getDescriptiveTextOnlyLayoutView().setVisibility(View.VISIBLE); 189 mDescriptiveTextOnlyTitle.setText(primaryText); 190 mDescriptiveTextOnlySubtitle.setText(secondaryText); 191 mDescriptiveTextOnlyOptionalImage.setImageDrawable(optionalImage); 192 mDescriptiveTextOnlyOptionalImage.setVisibility( 193 optionalImage == null ? View.GONE : View.VISIBLE); 194 mDescriptiveTextOnlyTapForMore.setText(tapForMoreText); 195 mDescriptiveTextOnlyTapForMore.setVisibility( 196 tapForMoreText == null ? View.GONE : View.VISIBLE); 197 } 198 updateDescriptiveTextWithControlsView(CharSequence primaryText, CharSequence secondaryText, Drawable optionalImage, DescriptiveTextWithControlsView.Control leftButton, DescriptiveTextWithControlsView.Control centerButton, DescriptiveTextWithControlsView.Control rightButton)199 protected final void updateDescriptiveTextWithControlsView(CharSequence primaryText, 200 CharSequence secondaryText, Drawable optionalImage, 201 DescriptiveTextWithControlsView.Control leftButton, 202 DescriptiveTextWithControlsView.Control centerButton, 203 DescriptiveTextWithControlsView.Control rightButton) { 204 getDescriptiveTextWithControlsLayoutView().setVisibility(View.VISIBLE); 205 mDescriptiveTextWithControlsTitle.setText(primaryText); 206 mDescriptiveTextWithControlsSubtitle.setText(secondaryText); 207 mDescriptiveTextWithControlsOptionalImage.setImageDrawable(optionalImage); 208 mDescriptiveTextWithControlsOptionalImage.setVisibility( 209 optionalImage == null ? View.GONE : View.VISIBLE); 210 211 updateControlBarButton(leftButton, mControlBarLeftButton); 212 updateControlBarButton(centerButton, mControlBarCenterButton); 213 updateControlBarButton(rightButton, mControlBarRightButton); 214 } 215 updateControlBarButton(DescriptiveTextWithControlsView.Control buttonContent, ImageButton buttonView)216 private void updateControlBarButton(DescriptiveTextWithControlsView.Control buttonContent, 217 ImageButton buttonView) { 218 if (buttonContent != null) { 219 buttonView.setImageDrawable(buttonContent.getIcon()); 220 buttonView.setOnClickListener(buttonContent.getOnClickListener()); 221 buttonView.setVisibility(View.VISIBLE); 222 } else { 223 buttonView.setVisibility(View.GONE); 224 } 225 } 226 updateTextBlock(CharSequence mainText, CharSequence tapForMoreText)227 protected final void updateTextBlock(CharSequence mainText, CharSequence tapForMoreText) { 228 getTextBlockLayoutView().setVisibility(View.VISIBLE); 229 mTextBlock.setText(mainText); 230 mTextBlockTapForMore.setText(tapForMoreText); 231 mTextBlockTapForMore.setVisibility(tapForMoreText == null ? View.GONE : View.VISIBLE); 232 } 233 hideAllViews()234 protected void hideAllViews() { 235 getTextBlockLayoutView().setVisibility(View.GONE); 236 getDescriptiveTextOnlyLayoutView().setVisibility(View.GONE); 237 getDescriptiveTextWithControlsLayoutView().setVisibility(View.GONE); 238 } 239 getRootView()240 protected final View getRootView() { 241 return mRootView; 242 } 243 getCardBackground()244 protected final View getCardBackground() { 245 if (mCardBackground == null) { 246 mCardBackground = getRootView().findViewById(R.id.card_background); 247 } 248 return mCardBackground; 249 } 250 getCardBackgroundImage()251 protected final CrossfadeImageView getCardBackgroundImage() { 252 if (mCardBackgroundImage == null) { 253 mCardBackgroundImage = getRootView().findViewById(R.id.card_background_image); 254 } 255 return mCardBackgroundImage; 256 } 257 getDescriptiveTextOnlyLayoutView()258 protected final View getDescriptiveTextOnlyLayoutView() { 259 if (mDescriptiveTextOnlyLayoutView == null) { 260 ViewStub stub = mRootView.findViewById(R.id.descriptive_text_layout); 261 mDescriptiveTextOnlyLayoutView = stub.inflate(); 262 mDescriptiveTextOnlyTitle = mDescriptiveTextOnlyLayoutView.findViewById( 263 R.id.primary_text); 264 mDescriptiveTextOnlySubtitle = mDescriptiveTextOnlyLayoutView.findViewById( 265 R.id.secondary_text); 266 mDescriptiveTextOnlyOptionalImage = mDescriptiveTextOnlyLayoutView.findViewById( 267 R.id.optional_image); 268 mDescriptiveTextOnlyTapForMore = mDescriptiveTextOnlyLayoutView.findViewById( 269 R.id.tap_for_more_text); 270 } 271 return mDescriptiveTextOnlyLayoutView; 272 } 273 getDescriptiveTextWithControlsLayoutView()274 protected final View getDescriptiveTextWithControlsLayoutView() { 275 if (mDescriptiveTextWithControlsLayoutView == null) { 276 ViewStub stub = mRootView.findViewById(R.id.descriptive_text_with_controls_layout); 277 mDescriptiveTextWithControlsLayoutView = stub.inflate(); 278 mDescriptiveTextWithControlsTitle = mDescriptiveTextWithControlsLayoutView.findViewById( 279 R.id.primary_text); 280 mDescriptiveTextWithControlsSubtitle = 281 mDescriptiveTextWithControlsLayoutView.findViewById(R.id.secondary_text); 282 mDescriptiveTextWithControlsOptionalImage = 283 mDescriptiveTextWithControlsLayoutView.findViewById(R.id.optional_image); 284 mControlBarView = mDescriptiveTextWithControlsLayoutView.findViewById(R.id.button_trio); 285 mControlBarLeftButton = mDescriptiveTextWithControlsLayoutView.findViewById( 286 R.id.button_left); 287 mControlBarCenterButton = mDescriptiveTextWithControlsLayoutView.findViewById( 288 R.id.button_center); 289 mControlBarRightButton = mDescriptiveTextWithControlsLayoutView.findViewById( 290 R.id.button_right); 291 } 292 return mDescriptiveTextWithControlsLayoutView; 293 } 294 getTextBlockLayoutView()295 private View getTextBlockLayoutView() { 296 if (mTextBlockLayoutView == null) { 297 ViewStub stub = mRootView.findViewById(R.id.text_block_layout); 298 mTextBlockLayoutView = stub.inflate(); 299 mTextBlock = mTextBlockLayoutView.findViewById(R.id.text_block); 300 mTextBlockTapForMore = mTextBlockLayoutView.findViewById(R.id.tap_for_more_text); 301 } 302 return mTextBlockLayoutView; 303 } 304 } 305