1 /* 2 * Copyright (C) 2014 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.example.android.justforus; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.net.Uri; 22 import android.os.Bundle; 23 import android.support.v4.app.ShareCompat; 24 import android.support.v7.app.AppCompatActivity; 25 import android.text.TextUtils; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.AdapterView; 30 import android.widget.AdapterView.OnItemClickListener; 31 import android.widget.BaseAdapter; 32 import android.widget.GridView; 33 import android.widget.ImageView; 34 import android.widget.TextView; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * Activity to display a grid of coupons. The number of columns varies based on screen width, 41 * and goes down to a one-column grid on a small device such as a phone. 42 * 43 * <p>A coupon consists of a photo, title, and subtitle. 44 * 45 * <p>Tapping on a coupon to redeem it brings up the Android "share" 46 * dialog with a pre-populated message based on the coupon text. 47 */ 48 public class MainActivity extends AppCompatActivity implements OnItemClickListener { 49 50 // Name of person giving out these coupons. When the user clicks on a coupon and shares 51 // to another app, this name will be part of the pre-populated text. 52 // TODO: Fill in your name here 53 private static final String SENDER_NAME = ""; 54 55 @Override onCreate(Bundle savedInstanceState)56 protected void onCreate(Bundle savedInstanceState) { 57 super.onCreate(savedInstanceState); 58 // Set activity_main.xml to be the layout for this activity 59 setContentView(R.layout.activity_main); 60 61 // Fetch the {@link LayoutInflater} service so that new views can be created 62 LayoutInflater inflater = (LayoutInflater) getSystemService( 63 Context.LAYOUT_INFLATER_SERVICE); 64 65 // Find the {@link GridView} that was already defined in the XML layout 66 GridView gridView = (GridView) findViewById(R.id.grid); 67 68 // Initialize the adapter with all the coupons. Set the adapter on the {@link GridView}. 69 gridView.setAdapter(new CouponAdapter(inflater, createAllCoupons())); 70 71 // Set a click listener for each coupon in the grid 72 gridView.setOnItemClickListener(this); 73 } 74 75 /** 76 * Generate the list of all coupons. 77 * @return The list of coupons. 78 */ createAllCoupons()79 private List<Coupon> createAllCoupons() { 80 // TODO: Customize this list of coupons for your personal use. 81 // You can add a title, subtitle, and a photo (in the assets directory). 82 List<Coupon> coupons = new ArrayList<Coupon>(); 83 coupons.add(new Coupon("Walk in the park" /* title */, 84 "Take a stroll in the flower garden" /* subtitle */, "park.jpg" /* image */)); 85 coupons.add(new Coupon("Trip to the zoo", 86 "See the cute zoo animals", "zoo.jpg")); 87 coupons.add(new Coupon("Watch sunrise", 88 "Drive out to the vista point and watch the sunrise at 6am", "sunrise.jpg")); 89 coupons.add(new Coupon("Hawaii getaway", 90 "Relax in Hawaii by going to the beach and attending luaus", "hawaii.jpg")); 91 coupons.add(new Coupon("Spa day", 92 "Receive a massage and enjoy the peace and quiet", "spa.jpg")); 93 coupons.add(new Coupon("Homemade dinner", 94 "Your favorite meal cooked by yours truly", "dinner.jpg")); 95 coupons.add(new Coupon("Day on the water", 96 "Boat ride down the river on a breezy day", "boat.jpg")); 97 coupons.add(new Coupon("Flowers", 98 "Delivered to your front door", "rose.jpg")); 99 coupons.add(new Coupon("Picnic", 100 "Wine, bread, and cheese at the vineyard", "picnic.jpg")); 101 coupons.add(new Coupon("Surprise gift", 102 "Won't be revealed until redeemed", "present.jpg")); 103 return coupons; 104 } 105 106 /** 107 * Callback method for a when a coupon is clicked. A new share intent is created with the 108 * coupon title. Then the user can select which app to share the content of the coupon with. 109 * 110 * @param parent The AdapterView where the click happened. 111 * @param view The view within the AdapterView that was clicked (this 112 * will be a view provided by the adapter). 113 * @param position The position of the view in the adapter. 114 * @param id The row id of the item that was clicked. 115 */ 116 @Override onItemClick(AdapterView<?> parent, View view, int position, long id)117 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 118 // Find coupon that was clicked based off of position in adapter 119 Coupon coupon = (Coupon) parent.getItemAtPosition(position); 120 121 // Create share intent 122 Intent shareIntent = ShareCompat.IntentBuilder.from(this) 123 .setText(getShareText(coupon)) 124 .setType("image/jpeg") 125 .setStream(coupon.mImageUri) 126 .setChooserTitle(getString(R.string.redeem_using)) 127 .createChooserIntent(); 128 startActivity(shareIntent); 129 } 130 131 /** 132 * Create the share intent text based on the coupon title, subtitle, and whether or not 133 * there is a {@link #SENDER_NAME}. 134 * 135 * @param coupon to create the intent text for. 136 * @return string to be used in the share intent. 137 */ getShareText(Coupon coupon)138 private String getShareText(Coupon coupon) { 139 // If there is no sender name, just use the coupon title and subtitle 140 if (TextUtils.isEmpty(SENDER_NAME)) { 141 return getString(R.string.message_format_without_sender, 142 coupon.mTitle, coupon.mSubtitle); 143 } else { 144 // Otherwise, use the other string template and pass in the {@link #SENDER_NAME} too 145 return getString(R.string.message_format_with_sender, SENDER_NAME, 146 coupon.mTitle, coupon.mSubtitle); 147 } 148 } 149 150 /** 151 * Adapter for grid of coupons. 152 */ 153 private static class CouponAdapter extends BaseAdapter { 154 155 private LayoutInflater mInflater; 156 private List<Coupon> mAllCoupons; 157 158 /** 159 * Constructs a new {@link CouponAdapter}. 160 * 161 * @param inflater to create new views 162 * @param allCoupons for list of all coupons to be displayed 163 */ CouponAdapter(LayoutInflater inflater, List<Coupon> allCoupons)164 public CouponAdapter(LayoutInflater inflater, List<Coupon> allCoupons) { 165 if (allCoupons == null) { 166 throw new IllegalStateException("Can't have null list of coupons"); 167 } 168 mAllCoupons = allCoupons; 169 mInflater = inflater; 170 } 171 172 @Override getCount()173 public int getCount() { 174 return mAllCoupons.size(); 175 } 176 177 @Override getItem(int position)178 public Coupon getItem(int position) { 179 return mAllCoupons.get(position); 180 } 181 182 @Override getItemId(int position)183 public long getItemId(int position) { 184 return position; 185 } 186 187 @Override getView(int position, View convertView, ViewGroup parent)188 public View getView(int position, View convertView, ViewGroup parent) { 189 View result = convertView; 190 if (result == null) { 191 result = mInflater.inflate(R.layout.grid_item, parent, false); 192 } 193 194 // Try to get view cache or create a new one if needed 195 ViewCache viewCache = (ViewCache) result.getTag(); 196 if (viewCache == null) { 197 viewCache = new ViewCache(result); 198 result.setTag(viewCache); 199 } 200 201 // Fetch item 202 Coupon coupon = getItem(position); 203 204 // Bind the data 205 viewCache.mTitleView.setText(coupon.mTitle); 206 viewCache.mSubtitleView.setText(coupon.mSubtitle); 207 viewCache.mImageView.setImageURI(coupon.mImageUri); 208 209 return result; 210 } 211 } 212 213 /** 214 * Cache of views in the grid item view to make recycling of views quicker. This avoids 215 * additional {@link View#findViewById(int)} calls after the {@link ViewCache} is first 216 * created for a view. See 217 * {@link CouponAdapter#getView(int position, View convertView, ViewGroup parent)}. 218 */ 219 private static class ViewCache { 220 221 /** View that displays the title of the coupon */ 222 private final TextView mTitleView; 223 224 /** View that displays the subtitle of the coupon */ 225 private final TextView mSubtitleView; 226 227 /** View that displays the image associated with the coupon */ 228 private final ImageView mImageView; 229 230 /** 231 * Constructs a new {@link ViewCache}. 232 * 233 * @param view which contains children views that should be cached. 234 */ ViewCache(View view)235 private ViewCache(View view) { 236 mTitleView = (TextView) view.findViewById(R.id.title); 237 mSubtitleView = (TextView) view.findViewById(R.id.subtitle); 238 mImageView = (ImageView) view.findViewById(R.id.image); 239 } 240 } 241 242 /** 243 * Model object for coupon. 244 */ 245 private static class Coupon { 246 247 /** Title of the coupon. */ 248 private final String mTitle; 249 250 /** Description of the coupon. */ 251 private final String mSubtitle; 252 253 /** Content URI of the image for the coupon. */ 254 private final Uri mImageUri; 255 256 /** 257 * Constructs a new {@link Coupon}. 258 * 259 * @param titleString is the title 260 * @param subtitleString is the description 261 * @param imageAssetFilePath is the file path from the application's assets folder for 262 * the image associated with this coupon 263 */ Coupon(String titleString, String subtitleString, String imageAssetFilePath)264 private Coupon(String titleString, String subtitleString, String imageAssetFilePath) { 265 mTitle = titleString; 266 mSubtitle = subtitleString; 267 mImageUri = Uri.parse("content://" + AssetProvider.CONTENT_URI + "/" + 268 imageAssetFilePath); 269 } 270 } 271 } 272