1 /*
2  * Copyright (C) 2017 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 package com.android.wallpaper.model;
17 
18 import android.app.Activity;
19 import android.content.Context;
20 import android.net.Uri;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.Log;
24 
25 import androidx.exifinterface.media.ExifInterface;
26 
27 import com.android.wallpaper.R;
28 import com.android.wallpaper.asset.Asset;
29 import com.android.wallpaper.asset.ContentUriAsset;
30 
31 import java.text.ParseException;
32 import java.text.SimpleDateFormat;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Date;
36 import java.util.List;
37 
38 /**
39  * Represents a wallpaper image from the system's image picker.
40  */
41 public class ImageWallpaperInfo extends WallpaperInfo {
42     public static final Parcelable.Creator<ImageWallpaperInfo> CREATOR =
43             new Parcelable.Creator<ImageWallpaperInfo>() {
44                 @Override
45                 public ImageWallpaperInfo createFromParcel(Parcel in) {
46                     return new ImageWallpaperInfo(in);
47                 }
48 
49                 @Override
50                 public ImageWallpaperInfo[] newArray(int size) {
51                     return new ImageWallpaperInfo[size];
52                 }
53             };
54     private static final String TAG = "ImageWallpaperInfo";
55     // Desired EXIF tags in descending order of priority.
56     private static final String[] EXIF_TAGS = {
57             ExifInterface.TAG_IMAGE_DESCRIPTION,
58             ExifInterface.TAG_ARTIST,
59             ExifInterface.TAG_DATETIME_ORIGINAL,
60             ExifInterface.TAG_MODEL,
61     };
62     private Uri mUri;
63     private ContentUriAsset mAsset;
64     private boolean mIsAssetUncached;
65 
ImageWallpaperInfo(Uri uri)66     public ImageWallpaperInfo(Uri uri) {
67         mUri = uri;
68     }
69 
ImageWallpaperInfo(Uri uri, boolean uncachedAsset)70     public ImageWallpaperInfo(Uri uri, boolean uncachedAsset) {
71         mUri = uri;
72         mIsAssetUncached = uncachedAsset;
73     }
74 
ImageWallpaperInfo(Parcel in)75     protected ImageWallpaperInfo(Parcel in) {
76         super(in);
77         mUri = Uri.parse(in.readString());
78     }
79 
80     @Override
getUri()81     public Uri getUri() {
82         return mUri;
83     }
84 
85     /**
86      * Formats a localized date string based on the provided datetime string in EXIF datetime format.
87      *
88      * @param exifDateTime Datetime string in EXIF datetime format.
89      * @return Localized date string, or the original datetime string if it could not be parsed.
90      */
formatDate(String exifDateTime)91     private static String formatDate(String exifDateTime) {
92         try {
93             Date parsedDate = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").parse(exifDateTime);
94             return SimpleDateFormat.getDateInstance().format(parsedDate);
95         } catch (ParseException e) {
96             Log.w(TAG, "Unable to parse image datetime", e);
97             return exifDateTime;
98         }
99     }
100 
getGenericAttributions(Context context)101     private static List<String> getGenericAttributions(Context context) {
102         return Arrays.asList(
103                 context.getResources().getString(R.string.my_photos_generic_wallpaper_title));
104     }
105 
106     @Override
getTitle(Context context)107     public String getTitle(Context context) {
108         return null;
109     }
110 
111     @Override
getAttributions(Context context)112     public List<String> getAttributions(Context context) {
113         ContentUriAsset asset = (ContentUriAsset) getAsset(context);
114 
115         if (!asset.isJpeg()) {
116             // Return generic attributions if image is not stored in the JPEG file format.
117             return getGenericAttributions(context);
118         }
119 
120         List<String> attributes = new ArrayList<>();
121 
122         for (String tag : EXIF_TAGS) {
123             String attribute = asset.readExifTag(tag);
124 
125             if (attribute == null) {
126                 continue;
127             }
128 
129             if (tag == ExifInterface.TAG_DATETIME_ORIGINAL) {
130                 attribute = formatDate(attribute);
131             }
132 
133             attributes.add(attribute);
134         }
135 
136         if (!attributes.isEmpty()) {
137             return attributes;
138         }
139 
140         // Return generic attributions if image did not contain any desired EXIF tags.
141         return getGenericAttributions(context);
142     }
143 
144     @Override
getAsset(Context context)145     public Asset getAsset(Context context) {
146         if (mIsAssetUncached) {
147             mAsset = new ContentUriAsset(
148                     context,
149                     mUri,
150                     /* uncached */ true);
151         } else {
152             if (mAsset == null) {
153                 mAsset = new ContentUriAsset(context, mUri);
154             }
155         }
156 
157         return mAsset;
158     }
159 
160     @Override
getThumbAsset(Context context)161     public Asset getThumbAsset(Context context) {
162         return getAsset(context);
163     }
164 
165     @Override
getCollectionId(Context context)166     public String getCollectionId(Context context) {
167         return context.getString(R.string.image_wallpaper_collection_id);
168     }
169 
170     @Override
showPreview(Activity srcActivity, InlinePreviewIntentFactory factory, int requestCode, boolean isAssetIdPresent)171     public void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory,
172                             int requestCode, boolean isAssetIdPresent) {
173         srcActivity.startActivityForResult(factory.newIntent(srcActivity, this,
174                 isAssetIdPresent), requestCode);
175     }
176 
177     @Override
writeToParcel(Parcel parcel, int i)178     public void writeToParcel(Parcel parcel, int i) {
179         super.writeToParcel(parcel, i);
180         parcel.writeString(mUri.toString());
181     }
182 }
183