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.android.fmradio;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.content.res.Resources;
22 import android.graphics.Bitmap;
23 import android.os.Environment;
24 import android.os.StatFs;
25 import android.os.storage.StorageManager;
26 import android.preference.PreferenceManager;
27 import android.util.Log;
28 import android.view.View.MeasureSpec;
29 import android.widget.LinearLayout;
30 import android.widget.TextView;
31 
32 import java.text.DecimalFormat;
33 import java.util.Locale;
34 
35 /**
36  * This class provider interface to compute station and frequency, get project
37  * string
38  */
39 public class FmUtils {
40     private static final String TAG = "FmUtils";
41 
42     // FM station variables
43     public static final int DEFAULT_STATION = 1000;
44     public static final float DEFAULT_STATION_FLOAT = computeFrequency(DEFAULT_STATION);
45     // maximum station frequency
46     private static final int HIGHEST_STATION = 1080;
47     // minimum station frequency
48     private static final int LOWEST_STATION = 875;
49     // station step
50     private static final int STEP = 1;
51     // convert rate
52     private static final int CONVERT_RATE = 10;
53 
54     // minimum storage space for record (512KB).
55     // Need to check before starting recording and during recording to avoid
56     // recording keeps going but there is no free space in sdcard.
57     public static final long LOW_SPACE_THRESHOLD = 512 * 1024;
58     // Different city may have different RDS information.
59     // We define 100 miles (160934.4m) to distinguish the cities.
60     public static final double LOCATION_DISTANCE_EXCEED = 160934.4;
61     private static final String FM_LOCATION_LATITUDE = "fm_location_latitude";
62     private static final String FM_LOCATION_LONGITUDE = "fm_location_longitude";
63     private static final String FM_IS_FIRST_TIME_PLAY = "fm_is_first_time_play";
64     private static final String FM_IS_FIRST_ENTER_STATION_LIST = "fm_is_first_enter_station_list";
65     // StorageManager For FM record
66     private static StorageManager sStorageManager = null;
67 
68     /**
69      * Whether the frequency is valid.
70      *
71      * @param station The FM station
72      *
73      * @return true if the frequency is in the valid scale, otherwise return
74      *         false
75      */
isValidStation(int station)76     public static boolean isValidStation(int station) {
77         boolean isValid = (station >= LOWEST_STATION && station <= HIGHEST_STATION);
78         return isValid;
79     }
80 
81     /**
82      * Compute increase station frequency
83      *
84      * @param station The station frequency
85      *
86      * @return station The frequency after increased
87      */
computeIncreaseStation(int station)88     public static int computeIncreaseStation(int station) {
89         int result = station + STEP;
90         if (result > HIGHEST_STATION) {
91             result = LOWEST_STATION;
92         }
93         return result;
94     }
95 
96     /**
97      * Compute decrease station frequency
98      *
99      * @param station The station frequency
100      *
101      * @return station The frequency after decreased
102      */
computeDecreaseStation(int station)103     public static int computeDecreaseStation(int station) {
104         int result = station - STEP;
105         if (result < LOWEST_STATION) {
106             result = HIGHEST_STATION;
107         }
108         return result;
109     }
110 
111     /**
112      * Compute station value with given frequency
113      *
114      * @param frequency The station frequency
115      *
116      * @return station The result value
117      */
computeStation(float frequency)118     public static int computeStation(float frequency) {
119         return (int) (frequency * CONVERT_RATE);
120     }
121 
122     /**
123      * Compute frequency value with given station
124      *
125      * @param station The station value
126      *
127      * @return station The frequency
128      */
computeFrequency(int station)129     public static float computeFrequency(int station) {
130         return (float) station / CONVERT_RATE;
131     }
132 
133     /**
134      * According station to get frequency string
135      *
136      * @param station for 100KZ, range 875-1080
137      *
138      * @return string like 87.5
139      */
formatStation(int station)140     public static String formatStation(int station) {
141         float frequency = (float) station / CONVERT_RATE;
142         DecimalFormat decimalFormat = new DecimalFormat("0.0");
143         return decimalFormat.format(frequency);
144     }
145 
146     /**
147      * Get the phone storage path
148      *
149      * @return The phone storage path
150      */
getDefaultStoragePath()151     public static String getDefaultStoragePath() {
152         return Environment.getExternalStorageDirectory().getPath();
153     }
154 
155     /**
156      * Get the default storage state
157      *
158      * @return The default storage state
159      */
getDefaultStorageState(Context context)160     public static String getDefaultStorageState(Context context) {
161         ensureStorageManager(context);
162         String state = sStorageManager.getVolumeState(getDefaultStoragePath());
163         return state;
164     }
165 
ensureStorageManager(Context context)166     private static void ensureStorageManager(Context context) {
167         if (sStorageManager == null) {
168             sStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
169         }
170     }
171 
172     /**
173      * Get the FM play list path
174      *
175      * @param context The context
176      *
177      * @return The FM play list path
178      */
getPlaylistPath(Context context)179     public static String getPlaylistPath(Context context) {
180         ensureStorageManager(context);
181         String[] externalStoragePaths = sStorageManager.getVolumePaths();
182         String path = externalStoragePaths[0] + "/Playlists/";
183         return path;
184     }
185 
186     /**
187      * Check if has enough space for record
188      *
189      * @param recordingSdcard The recording sdcard path
190      *
191      * @return true if has enough space for record
192      */
hasEnoughSpace(String recordingSdcard)193     public static boolean hasEnoughSpace(String recordingSdcard) {
194         boolean ret = false;
195         try {
196             StatFs fs = new StatFs(recordingSdcard);
197             long blocks = fs.getAvailableBlocks();
198             long blockSize = fs.getBlockSize();
199             long spaceLeft = blocks * blockSize;
200             ret = spaceLeft > LOW_SPACE_THRESHOLD ? true : false;
201         } catch (IllegalArgumentException e) {
202             Log.e(TAG, "hasEnoughSpace, sdcard may be unmounted:" + recordingSdcard);
203         }
204         return ret;
205     }
206 
207     /**
208      * Get the latest searched location
209      * @return the list of latitude and longitude
210      */
getLastSearchedLocation(Context context)211     public static double[] getLastSearchedLocation(Context context) {
212         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
213 
214         String strLatitude = prefs.getString(FM_LOCATION_LATITUDE, "0.0");
215         String strLongitude = prefs.getString(FM_LOCATION_LONGITUDE, "0.0");
216         double latitude = Double.valueOf(strLatitude);
217         double longitude = Double.valueOf(strLongitude);
218         return new double[] { latitude, longitude };
219     }
220 
221     /**
222      * Set the last searched location
223      */
setLastSearchedLocation(Context context, double latitude, double longitude)224     public static void setLastSearchedLocation(Context context, double latitude, double longitude) {
225         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
226         SharedPreferences.Editor editor = prefs.edit();
227         String strLatitude = Double.valueOf(latitude).toString();
228         String strLongitude = Double.valueOf(longitude).toString();
229         editor.putString(FM_LOCATION_LATITUDE, strLatitude);
230         editor.putString(FM_LOCATION_LONGITUDE, strLongitude);
231         editor.commit();
232     }
233 
234     /**
235      * check it is the first time to use Fm
236      */
isFirstTimePlayFm(Context context)237     public static boolean isFirstTimePlayFm(Context context) {
238         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
239         boolean isFirstTime = prefs.getBoolean(FM_IS_FIRST_TIME_PLAY, true);
240         return isFirstTime;
241     }
242 
243     /**
244      * Called when first time play FM.
245      * @param context The context
246      */
setIsFirstTimePlayFm(Context context)247     public static void setIsFirstTimePlayFm(Context context) {
248         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
249         SharedPreferences.Editor editor = prefs.edit();
250         editor.putBoolean(FM_IS_FIRST_TIME_PLAY, false);
251         editor.commit();
252     }
253 
254     /**
255      * check it is the first time enter into station list page
256      */
isFirstEnterStationList(Context context)257     public static boolean isFirstEnterStationList(Context context) {
258         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
259         boolean isFirstEnter = prefs.getBoolean(FM_IS_FIRST_ENTER_STATION_LIST, true);
260         if (isFirstEnter) {
261             SharedPreferences.Editor editor = prefs.edit();
262             editor.putBoolean(FM_IS_FIRST_ENTER_STATION_LIST, false);
263             editor.commit();
264         }
265         return isFirstEnter;
266     }
267 
268     /**
269      * Create the notification large icon bitmap from layout
270      * @param c The context
271      * @param text The frequency text
272      * @return The large icon bitmap with frequency text
273      */
createNotificationLargeIcon(Context c, String text)274     public static Bitmap createNotificationLargeIcon(Context c, String text) {
275         Resources res = c.getResources();
276         int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width);
277         int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height);
278         LinearLayout iconLayout = new LinearLayout(c);
279         iconLayout.setOrientation(LinearLayout.VERTICAL);
280         iconLayout.setBackgroundColor(c.getResources().getColor(R.color.theme_primary_color));
281         iconLayout.setDrawingCacheEnabled(true);
282         iconLayout.layout(0, 0, width, height);
283         TextView iconText = new TextView(c);
284         iconText.setTextSize(24.0f);
285         iconText.setTextColor(res.getColor(R.color.theme_title_color));
286         iconText.setText(text);
287         iconText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
288                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
289         int left = (int) ((width - iconText.getMeasuredWidth()) * 0.5);
290         int top = (int) ((height - iconText.getMeasuredHeight()) * 0.5);
291         iconText.layout(left, top, iconText.getMeasuredWidth() + left,
292                 iconText.getMeasuredHeight() + top);
293         iconLayout.addView(iconText);
294         iconLayout.layout(0, 0, width, height);
295 
296         iconLayout.buildDrawingCache();
297         Bitmap largeIcon = Bitmap.createBitmap(iconLayout.getDrawingCache());
298         iconLayout.destroyDrawingCache();
299         return largeIcon;
300     }
301 }
302