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_SPEAKER_MODE = "fm_is_speaker_mode"; 65 private static final String FM_IS_FIRST_ENTER_STATION_LIST = "fm_is_first_enter_station_list"; 66 // StorageManager For FM record 67 private static StorageManager sStorageManager = null; 68 69 /** 70 * Whether the frequency is valid. 71 * 72 * @param station The FM station 73 * 74 * @return true if the frequency is in the valid scale, otherwise return 75 * false 76 */ isValidStation(int station)77 public static boolean isValidStation(int station) { 78 boolean isValid = (station >= LOWEST_STATION && station <= HIGHEST_STATION); 79 return isValid; 80 } 81 82 /** 83 * Compute increase station frequency 84 * 85 * @param station The station frequency 86 * 87 * @return station The frequency after increased 88 */ computeIncreaseStation(int station)89 public static int computeIncreaseStation(int station) { 90 int result = station + STEP; 91 if (result > HIGHEST_STATION) { 92 result = LOWEST_STATION; 93 } 94 return result; 95 } 96 97 /** 98 * Compute decrease station frequency 99 * 100 * @param station The station frequency 101 * 102 * @return station The frequency after decreased 103 */ computeDecreaseStation(int station)104 public static int computeDecreaseStation(int station) { 105 int result = station - STEP; 106 if (result < LOWEST_STATION) { 107 result = HIGHEST_STATION; 108 } 109 return result; 110 } 111 112 /** 113 * Compute station value with given frequency 114 * 115 * @param frequency The station frequency 116 * 117 * @return station The result value 118 */ computeStation(float frequency)119 public static int computeStation(float frequency) { 120 return (int) (frequency * CONVERT_RATE); 121 } 122 123 /** 124 * Compute frequency value with given station 125 * 126 * @param station The station value 127 * 128 * @return station The frequency 129 */ computeFrequency(int station)130 public static float computeFrequency(int station) { 131 return (float) station / CONVERT_RATE; 132 } 133 134 /** 135 * According station to get frequency string 136 * 137 * @param station for 100KZ, range 875-1080 138 * 139 * @return string like 87.5 140 */ formatStation(int station)141 public static String formatStation(int station) { 142 float frequency = (float) station / CONVERT_RATE; 143 DecimalFormat decimalFormat = new DecimalFormat("0.0"); 144 return decimalFormat.format(frequency); 145 } 146 147 /** 148 * Get the phone storage path 149 * 150 * @return The phone storage path 151 */ getDefaultStoragePath()152 public static String getDefaultStoragePath() { 153 return Environment.getExternalStorageDirectory().getPath(); 154 } 155 156 /** 157 * Get the default storage state 158 * 159 * @return The default storage state 160 */ getDefaultStorageState(Context context)161 public static String getDefaultStorageState(Context context) { 162 ensureStorageManager(context); 163 String state = sStorageManager.getVolumeState(getDefaultStoragePath()); 164 return state; 165 } 166 ensureStorageManager(Context context)167 private static void ensureStorageManager(Context context) { 168 if (sStorageManager == null) { 169 sStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); 170 } 171 } 172 173 /** 174 * Get the FM play list path 175 * 176 * @param context The context 177 * 178 * @return The FM play list path 179 */ getPlaylistPath(Context context)180 public static String getPlaylistPath(Context context) { 181 ensureStorageManager(context); 182 String[] externalStoragePaths = sStorageManager.getVolumePaths(); 183 String path = externalStoragePaths[0] + "/Playlists/"; 184 return path; 185 } 186 187 /** 188 * Check if has enough space for record 189 * 190 * @param recordingSdcard The recording sdcard path 191 * 192 * @return true if has enough space for record 193 */ hasEnoughSpace(String recordingSdcard)194 public static boolean hasEnoughSpace(String recordingSdcard) { 195 boolean ret = false; 196 try { 197 StatFs fs = new StatFs(recordingSdcard); 198 long blocks = fs.getAvailableBlocks(); 199 long blockSize = fs.getBlockSize(); 200 long spaceLeft = blocks * blockSize; 201 ret = spaceLeft > LOW_SPACE_THRESHOLD ? true : false; 202 } catch (IllegalArgumentException e) { 203 Log.e(TAG, "hasEnoughSpace, sdcard may be unmounted:" + recordingSdcard); 204 } 205 return ret; 206 } 207 208 /** 209 * Get the latest searched location 210 * @return the list of latitude and longitude 211 */ getLastSearchedLocation(Context context)212 public static double[] getLastSearchedLocation(Context context) { 213 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 214 215 String strLatitude = prefs.getString(FM_LOCATION_LATITUDE, "0.0"); 216 String strLongitude = prefs.getString(FM_LOCATION_LONGITUDE, "0.0"); 217 double latitude = Double.valueOf(strLatitude); 218 double longitude = Double.valueOf(strLongitude); 219 return new double[] { latitude, longitude }; 220 } 221 222 /** 223 * Set the last searched location 224 */ setLastSearchedLocation(Context context, double latitude, double longitude)225 public static void setLastSearchedLocation(Context context, double latitude, double longitude) { 226 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 227 SharedPreferences.Editor editor = prefs.edit(); 228 String strLatitude = Double.valueOf(latitude).toString(); 229 String strLongitude = Double.valueOf(longitude).toString(); 230 editor.putString(FM_LOCATION_LATITUDE, strLatitude); 231 editor.putString(FM_LOCATION_LONGITUDE, strLongitude); 232 editor.commit(); 233 } 234 235 /** 236 * check it is the first time to use Fm 237 */ isFirstTimePlayFm(Context context)238 public static boolean isFirstTimePlayFm(Context context) { 239 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 240 boolean isFirstTime = prefs.getBoolean(FM_IS_FIRST_TIME_PLAY, true); 241 return isFirstTime; 242 } 243 244 /** 245 * Called when first time play FM. 246 * @param context The context 247 */ setIsFirstTimePlayFm(Context context)248 public static void setIsFirstTimePlayFm(Context context) { 249 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 250 SharedPreferences.Editor editor = prefs.edit(); 251 editor.putBoolean(FM_IS_FIRST_TIME_PLAY, false); 252 editor.commit(); 253 } 254 255 /** 256 * check it is the first time enter into station list page 257 */ isFirstEnterStationList(Context context)258 public static boolean isFirstEnterStationList(Context context) { 259 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 260 boolean isFirstEnter = prefs.getBoolean(FM_IS_FIRST_ENTER_STATION_LIST, true); 261 if (isFirstEnter) { 262 SharedPreferences.Editor editor = prefs.edit(); 263 editor.putBoolean(FM_IS_FIRST_ENTER_STATION_LIST, false); 264 editor.commit(); 265 } 266 return isFirstEnter; 267 } 268 269 /** 270 * Create the notification large icon bitmap from layout 271 * @param c The context 272 * @param text The frequency text 273 * @return The large icon bitmap with frequency text 274 */ createNotificationLargeIcon(Context c, String text)275 public static Bitmap createNotificationLargeIcon(Context c, String text) { 276 Resources res = c.getResources(); 277 int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width); 278 int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height); 279 LinearLayout iconLayout = new LinearLayout(c); 280 iconLayout.setOrientation(LinearLayout.VERTICAL); 281 iconLayout.setBackgroundColor(c.getResources().getColor(R.color.theme_primary_color)); 282 iconLayout.setDrawingCacheEnabled(true); 283 iconLayout.layout(0, 0, width, height); 284 TextView iconText = new TextView(c); 285 iconText.setTextSize(24.0f); 286 iconText.setTextColor(res.getColor(R.color.theme_title_color)); 287 iconText.setText(text); 288 iconText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 289 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 290 int left = (int) ((width - iconText.getMeasuredWidth()) * 0.5); 291 int top = (int) ((height - iconText.getMeasuredHeight()) * 0.5); 292 iconText.layout(left, top, iconText.getMeasuredWidth() + left, 293 iconText.getMeasuredHeight() + top); 294 iconLayout.addView(iconText); 295 iconLayout.layout(0, 0, width, height); 296 297 iconLayout.buildDrawingCache(); 298 Bitmap largeIcon = Bitmap.createBitmap(iconLayout.getDrawingCache()); 299 iconLayout.destroyDrawingCache(); 300 return largeIcon; 301 } 302 303 /** 304 * Get whether speaker mode is in use when audio focus lost. 305 * @param context the Context 306 * @return true for speaker mode, false for non speaker mode 307 */ getIsSpeakerModeOnFocusLost(Context context)308 public static boolean getIsSpeakerModeOnFocusLost(Context context) { 309 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 310 311 return prefs.getBoolean(FM_IS_SPEAKER_MODE, false); 312 } 313 314 /** 315 * Set whether speaker mode is in use. 316 * @param context the Context 317 * @param isSpeaker speaker state 318 */ setIsSpeakerModeOnFocusLost(Context context, boolean isSpeaker)319 public static void setIsSpeakerModeOnFocusLost(Context context, boolean isSpeaker) { 320 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 321 SharedPreferences.Editor editor = prefs.edit(); 322 editor.putBoolean(FM_IS_SPEAKER_MODE, isSpeaker); 323 editor.commit(); 324 } 325 } 326