2 * Copyright (C) 2011 The CyanogenMod Project
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.android.music;
\r
19 import java.io.File;
\r
20 import java.io.FileInputStream;
\r
21 import java.io.FileNotFoundException;
\r
22 import java.io.FileOutputStream;
\r
23 import java.io.IOException;
\r
24 import java.nio.channels.FileChannel;
\r
25 import java.util.List;
\r
27 import android.app.ActionBar;
\r
28 import android.app.AlertDialog;
\r
29 import android.app.WallpaperManager;
\r
30 import android.content.ActivityNotFoundException;
\r
31 import android.content.DialogInterface;
\r
32 import android.content.Intent;
\r
33 import android.content.SharedPreferences;
\r
34 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
\r
35 import android.content.pm.PackageInfo;
\r
36 import android.content.pm.PackageManager;
\r
37 import android.content.pm.PackageManager.NameNotFoundException;
\r
38 import android.content.pm.ResolveInfo;
\r
39 import android.content.res.Resources;
\r
40 import android.graphics.Bitmap;
\r
41 import android.graphics.BitmapFactory;
\r
42 import android.media.audiofx.AudioEffect;
\r
43 import android.net.Uri;
\r
44 import android.os.Build;
\r
45 import android.os.Bundle;
\r
46 import android.os.Environment;
\r
47 import android.os.SystemClock;
\r
48 import android.preference.CheckBoxPreference;
\r
49 import android.preference.ListPreference;
\r
50 import android.preference.Preference;
\r
51 import android.preference.Preference.OnPreferenceChangeListener;
\r
52 import android.preference.Preference.OnPreferenceClickListener;
\r
53 import android.preference.PreferenceActivity;
\r
54 import android.preference.PreferenceManager;
\r
55 import android.preference.PreferenceScreen;
\r
56 import android.provider.MediaStore;
\r
57 import android.util.Log;
\r
58 import android.view.MenuItem;
\r
59 import android.view.View;
\r
60 import android.widget.ImageView;
\r
61 import android.widget.LinearLayout;
\r
62 import android.widget.Toast;
\r
64 public class MusicSettingsActivity extends PreferenceActivity implements
\r
65 OnSharedPreferenceChangeListener, OnPreferenceChangeListener {
\r
67 static final String KEY_ENABLE_FOCUS_LOSS_DUCKING = "enable_focus_loss_ducking";
\r
68 static final String KEY_DUCK_ATTENUATION_DB = "duck_attenuation_db";
\r
69 static final String KEY_BACK_BUTTON_DB = "back_button_db";
\r
70 static final String KEY_ANIMATION_UI_DB = "animation_ui_db";
\r
71 static final String KEY_ENABLE_GESTURES = "enable_gestures";
\r
72 static final String KEY_ENABLE_HAPTIC_FEEDBACK = "enable_haptic_feedback";
\r
73 static final String KEY_HAS_CUSTOM_GESTURES = "has_custom_gestures";
\r
74 static final String KEY_ENABLE_SEARCH_BUTTON = "cbSearch";
\r
75 static final String KEY_ENABLE_PLAY_BUTTON = "cbPlay";
\r
76 static final String KEY_ENABLE_NEXT_BUTTON = "cbNext";
\r
77 static final String KEY_ENABLE_PREV_BUTTON = "cbPrev";
\r
78 static final String KEY_ENABLE_NEW_PLAYLIST_BUTTON = "cbPlaylist";
\r
79 static final String KEY_ENABLE_ALBUM_ART = "cbArt";
\r
80 static final String KEY_ENABLE_SONG_TEXT = "tvLine1";
\r
81 static final String KEY_ENABLE_ARTIST_TEXT = "tvLine2";
\r
82 static final String KEY_ENABLE_ALBUM_TEXT = "tvLine3";
\r
83 static final String KEY_COLOR_PREFERENCE_KEY = "color";
\r
84 static final String KEY_ENABLE_STATUS_PLAY_BUTTON = "cbStatusPlay";
\r
85 static final String KEY_ENABLE_SHARE_BUTTON = "cbShare";
\r
86 static final String KEY_ENABLE_PROGRESS_BAR = "cbProgress";
\r
87 static final String KEY_ENABLE_OVER_FLOW = "cbFlow";
\r
89 static final String KEY_ENABLE_STATUS_NEXT_BUTTON = "cbStatusNext";
\r
90 static final String KEY_ENABLE_STATUS_PREV_BUTTON = "cbStatusPrev";
\r
91 static final String KEY_ENABLE_STATUS_ALBUM_ART = "cbStatusArt";
\r
92 static final String KEY_ENABLE_STATUS_SONG_TEXT = "tvStatusLine1";
\r
93 static final String KEY_ENABLE_STATUS_ARTIST_TEXT = "tvStatusLine2";
\r
94 static final String KEY_ENABLE_STATUS_ALBUM_TEXT = "tvStatusLine3";
\r
95 static final String KEY_ENABLE_MARKET_SERACH = "cbMarket";
\r
96 static final String KEY_ENABLE_STATUS_COLLAPSE = "cbStatusCollapse";
\r
97 static final String SCREENSAVER_COLOR = "screensaver_color";
\r
98 static final String SCREENSAVER_COLOR_ALPHA = "screensaver_color_alpha";
\r
99 static final String SCREENSAVER_COLOR_RED = "screensaver_color_red";
\r
100 static final String SCREENSAVER_COLOR_GREEN = "screensaver_color_green";
\r
101 static final String SCREENSAVER_COLOR_BLUE = "screensaver_color_blue";
\r
102 static final String KEY_ENTER_FULL_NOW_PLAYING = "cbEnterNowPlaying";
\r
103 static final String KEY_ENABLE_STATUS_TEXT_COLOR = "tvStatusColor";
\r
104 static final String KEY_ENABLE_HOME_ART = "cbHomeAlbumArt";
\r
105 static final String KEY_LOCK = "cbLock";
\r
106 public static final String THEME_DEFAULT = "Music";
\r
107 static final String THEME_KEY = "themePackageName";
\r
108 static final String SHAKE_SENSITIVITY = "shake_sensitivity";
\r
109 static final String FLIP_SENSITIVITY = "flip_sensitivity";
\r
111 // This key has the gesture entry name (E.g. PAUSE) appended to it before
\r
113 static final String KEY_HAS_CUSTOM_GESTURE_XXX = "has_custom_gesture_";
\r
115 static final String DEFAULT_DUCK_ATTENUATION_DB = "8";
\r
116 static final String DEFAULT_BACK_BUTTON_ACTION_DB = "0";
\r
118 static final String ACTION_ENABLE_GESTURES_CHANGED = "com.android.music.enablegestureschanged";
\r
119 static final String ACTION_GESTURES_CHANGED = "com.android.music.gestureschanged";
\r
121 static final String PREFERENCES_FILE = "settings";
\r
122 public static final String KEY_ENABLE_STATUS_NONYA = "cbStatusNonya";
\r
123 public static final String KEY_BUILD_VERSION = "build";
\r
124 public static final String KEY_SOUND_EFFECT = "eqEffects";
\r
125 public static final String KEY_FEEDBACK = "feedback";
\r
126 public static final String KEY_FLIP = "cbFlip";
\r
127 public static final String KEY_TICK = "cbStatusTicker";
\r
129 long[] mHits = new long[3];
\r
130 private static final String LOG_TAG = "EasterEgg";
\r
131 private static final int EFFECTS_PANEL = 0;
\r
133 // Color to use for text & graphics in screen saver mode.
\r
134 static final int DEFAULT_SCREENSAVER_COLOR_ALPHA = 230;
\r
135 static final int DEFAULT_SCREENSAVER_COLOR_RED = 0;
\r
136 static final int DEFAULT_SCREENSAVER_COLOR_GREEN = 192;
\r
137 static final int DEFAULT_SCREENSAVER_COLOR_BLUE = 255;
\r
138 // Custom wallpaper
\r
139 static final String BG_PHOTO_FILE = "home_art";
\r
140 static final String TEMP_PHOTO_FILE = "home";
\r
141 private Bitmap bgBitmap = null;
\r
142 // Shake and Flip sensitivity
\r
143 static final double DEFAULT_SHAKE_SENS = 2;
\r
144 static final int DEFAULT_FLIP_SENS = 10;
\r
146 public AlertDialog themeAlert;
\r
147 public CheckBoxPreference cp;
\r
150 protected void onCreate(Bundle savedInstanceState) {
\r
151 super.onCreate(savedInstanceState);
\r
153 PreferenceManager preferenceManager = getPreferenceManager();
\r
154 preferenceManager.setSharedPreferencesName(PREFERENCES_FILE);
\r
155 addPreferencesFromResource(R.xml.settings);
\r
157 ActionBar bar = getActionBar();
\r
158 bar.setDisplayHomeAsUpEnabled(true);
\r
160 PreferenceScreen screen;
\r
161 screen = getPreferenceScreen();
\r
163 cp = (CheckBoxPreference) screen.findPreference("cbHomeAlbumArt");
\r
165 final CheckBoxPreference lk = (CheckBoxPreference) screen
\r
166 .findPreference("cbLock");
\r
168 AlertDialog.Builder builder = new AlertDialog.Builder(this);
\r
169 builder.setTitle("Set Wallpaper");
\r
170 builder.setIcon(android.R.drawable.ic_menu_crop);
\r
171 builder.setMessage(
\r
172 "You should select a wallpaper to use when your music is paused.")
\r
173 .setCancelable(false)
\r
174 .setPositiveButton("Okay",
\r
175 new DialogInterface.OnClickListener() {
\r
176 public void onClick(DialogInterface dialog, int id) {
\r
180 .setNegativeButton("Cancel",
\r
181 new DialogInterface.OnClickListener() {
\r
182 public void onClick(DialogInterface dialog, int id) {
\r
184 cp.setChecked(false);
\r
187 final AlertDialog alert = builder.create();
\r
189 AlertDialog.Builder lock = new AlertDialog.Builder(this);
\r
190 lock.setTitle("Requires Restart");
\r
191 lock.setIcon(R.drawable.ic_dialog_alert_holo_dark);
\r
193 "Music needs to stop completely and restart to let the changes take effect")
\r
194 .setCancelable(false)
\r
195 .setPositiveButton("Okay",
\r
196 new DialogInterface.OnClickListener() {
\r
197 public void onClick(DialogInterface dialog, int id) {
\r
198 // This isn't a good practice, but we need to
\r
200 // service completely to see the change
\r
205 .setNegativeButton("Cancel",
\r
206 new DialogInterface.OnClickListener() {
\r
207 public void onClick(DialogInterface dialog, int id) {
\r
209 if (lk.isChecked()) {
\r
210 lk.setChecked(false);
\r
212 lk.setChecked(true);
\r
216 final AlertDialog lockAlert = lock.create();
\r
218 cp.setOnPreferenceClickListener(new OnPreferenceClickListener() {
\r
219 public boolean onPreferenceClick(final Preference preference) {
\r
220 CheckBoxPreference cbp = (CheckBoxPreference) preference;
\r
221 if (cbp.isChecked()) {
\r
224 // We don't want the wall paper to remain the album art if
\r
225 // they aren't using this.
\r
226 setCustomBackground();
\r
232 lk.setOnPreferenceClickListener(new OnPreferenceClickListener() {
\r
233 public boolean onPreferenceClick(final Preference preference) {
\r
240 PackageInfo packageInfo = getPackageManager().getPackageInfo(
\r
241 getPackageName(), 0);
\r
242 findPreference(KEY_BUILD_VERSION).setSummary(
\r
243 Build.VERSION.RELEASE + " - " + packageInfo.versionName);
\r
244 } catch (NameNotFoundException e) {
\r
245 findPreference(KEY_BUILD_VERSION).setSummary("?");
\r
247 // ADW: theme settings
\r
248 SharedPreferences sp = getPreferenceManager().getSharedPreferences();
\r
249 final String themePackage = sp.getString(THEME_KEY, THEME_DEFAULT);
\r
250 ListPreference themeLp = (ListPreference) findPreference(THEME_KEY);
\r
251 themeLp.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
\r
252 public boolean onPreferenceChange(Preference preference,
\r
254 PreviewPreference themePreview = (PreviewPreference) findPreference("themePreview");
\r
255 themePreview.setTheme(newValue.toString());
\r
260 Intent intent = new Intent("com.andrew.music.THEMES");
\r
261 intent.addCategory("android.intent.category.DEFAULT");
\r
262 PackageManager pm = getPackageManager();
\r
263 List<ResolveInfo> themes = pm.queryIntentActivities(intent, 0);
\r
264 String[] entries = new String[themes.size() + 1];
\r
265 String[] values = new String[themes.size() + 1];
\r
266 entries[0] = MusicSettingsActivity.THEME_DEFAULT;
\r
267 values[0] = MusicSettingsActivity.THEME_DEFAULT;
\r
268 for (int i = 0; i < themes.size(); i++) {
\r
269 String appPackageName = (themes.get(i)).activityInfo.packageName
\r
271 String themeName = (themes.get(i)).loadLabel(pm).toString();
\r
272 entries[i + 1] = themeName;
\r
273 values[i + 1] = appPackageName;
\r
275 themeLp.setEntries(entries);
\r
276 themeLp.setEntryValues(values);
\r
277 PreviewPreference themePreview = (PreviewPreference) findPreference("themePreview");
\r
278 themePreview.setTheme(themePackage);
\r
281 private void pickImage() {
\r
282 Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
\r
283 intent.setType("image/*");
\r
285 intent.putExtra("crop", "true");
\r
286 intent.putExtra("scale", true);
\r
287 intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
\r
288 intent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
\r
289 intent.putExtra("noFaceDetection", true);
\r
291 startActivityForResult(intent, 0);
\r
294 private Uri getTempUri() {
\r
295 return Uri.fromFile(getTempFile());
\r
298 private File getTempFile() {
\r
299 if (isSDCARDMounted()) {
\r
301 File f = new File(Environment.getExternalStorageDirectory(),
\r
304 // f.createNewFile();
\r
305 // } catch (IOException e) {
\r
306 // TODO Auto-generated catch block
\r
307 // e.printStackTrace();
\r
308 // Toast.makeText(this, "Something Fucked Up",
\r
309 // Toast.LENGTH_LONG).show();
\r
317 private boolean isSDCARDMounted() {
\r
318 String status = Environment.getExternalStorageState();
\r
320 if (status.equals(Environment.MEDIA_MOUNTED))
\r
325 public static void copyFile(File src, File dst) throws IOException {
\r
326 FileChannel inChannel = new FileInputStream(src).getChannel();
\r
327 FileChannel outChannel = new FileOutputStream(dst).getChannel();
\r
330 inChannel.transferTo(0, inChannel.size(), outChannel);
\r
333 if (inChannel != null)
\r
335 if (outChannel != null)
\r
336 outChannel.close();
\r
340 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
\r
341 if (requestCode == 0) {
\r
342 if (resultCode == RESULT_OK) {
\r
345 File src = getTempFile();
\r
346 File dst = new File(getFilesDir(), BG_PHOTO_FILE);
\r
347 copyFile(src, dst);
\r
349 } catch (FileNotFoundException e) {
\r
350 // TODO Auto-generated catch block
\r
351 e.printStackTrace();
\r
352 } catch (IOException e) {
\r
353 // TODO Auto-generated catch block
\r
354 e.printStackTrace();
\r
360 // Set Custom Background Image
\r
361 public void setCustomBackground() {
\r
363 SharedPreferences preferences = getSharedPreferences(
\r
364 MusicSettingsActivity.PREFERENCES_FILE, MODE_PRIVATE);
\r
367 .getBoolean(MusicSettingsActivity.KEY_ENABLE_HOME_ART, false);
\r
369 // First clean our old data
\r
370 if (bgBitmap != null) {
\r
371 bgBitmap.recycle();
\r
375 // now load the proper bg
\r
376 String BG_FILE = getFilesDir().toString() + File.separator
\r
377 + MusicSettingsActivity.BG_PHOTO_FILE;
\r
378 bgBitmap = BitmapFactory.decodeFile(BG_FILE);
\r
381 WallpaperManager.getInstance(this).setBitmap(bgBitmap);
\r
382 } catch (Exception e) {
\r
383 // TODO Auto-generated catch block
\r
384 e.printStackTrace();
\r
388 public void applyTheme(View v) {
\r
389 PreviewPreference themePreview = (PreviewPreference) findPreference("themePreview");
\r
390 String packageName = themePreview.getValue().toString();
\r
391 // this time we really save the themepackagename
\r
392 SharedPreferences sp = getPreferenceManager().getSharedPreferences();
\r
393 final SharedPreferences.Editor editor = sp.edit();
\r
394 editor.putString("themePackageName", packageName);
\r
395 // and update the preferences from the theme
\r
396 // TODO:ADW maybe this should be optional for the user
\r
397 if (!packageName.equals(MusicSettingsActivity.THEME_DEFAULT)) {
\r
398 Resources themeResources = null;
\r
400 themeResources = getPackageManager()
\r
401 .getResourcesForApplication(packageName.toString());
\r
402 } catch (NameNotFoundException e) {
\r
403 // e.printStackTrace();
\r
408 AlertDialog.Builder theme = new AlertDialog.Builder(this);
\r
409 theme.setTitle("Requires Restart");
\r
410 theme.setIcon(R.drawable.ic_dialog_alert_holo_dark);
\r
412 "Music needs to stop completely and restart to let the changes take effect")
\r
413 .setCancelable(false)
\r
414 .setPositiveButton("Okay",
\r
415 new DialogInterface.OnClickListener() {
\r
416 public void onClick(DialogInterface dialog, int id) {
\r
418 // This isn't a good practice, but we need to
\r
420 // service completely to see the change
\r
425 .setNegativeButton("Cancel",
\r
426 new DialogInterface.OnClickListener() {
\r
427 public void onClick(DialogInterface dialog, int id) {
\r
431 themeAlert = theme.create();
\r
435 public void getThemes(View v) {
\r
436 // TODO:warn theme devs to use "MusicTheme" as keyword.
\r
437 Uri marketUri = Uri.parse("market://search?q=MusicTheme");
\r
438 Intent marketIntent = new Intent(Intent.ACTION_VIEW).setData(marketUri);
\r
440 startActivity(marketIntent);
\r
441 } catch (ActivityNotFoundException e) {
\r
442 Toast.makeText(this, R.string.activity_not_found,
\r
443 Toast.LENGTH_SHORT).show();
\r
444 } catch (SecurityException e) {
\r
445 Toast.makeText(this, R.string.activity_not_found,
\r
446 Toast.LENGTH_SHORT).show();
\r
447 Log.e("Music", "Get themes", e);
\r
453 public boolean onOptionsItemSelected(MenuItem item) {
\r
454 switch (item.getItemId()) {
\r
455 case android.R.id.home:
\r
456 super.onBackPressed();
\r
459 return super.onOptionsItemSelected(item);
\r
463 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
\r
465 if (key.equals(KEY_ENABLE_GESTURES)) {
\r
466 Intent intent = new Intent(ACTION_ENABLE_GESTURES_CHANGED);
\r
467 sendBroadcast(intent);
\r
472 protected void onResume() {
\r
474 getPreferenceScreen().getSharedPreferences()
\r
475 .registerOnSharedPreferenceChangeListener(this);
\r
479 protected void onPause() {
\r
481 getPreferenceScreen().getSharedPreferences()
\r
482 .unregisterOnSharedPreferenceChangeListener(this);
\r
486 protected void onDestroy() {
\r
492 public boolean onPreferenceChange(Preference arg0, Object arg1) {
\r
493 // TODO Auto-generated method stub
\r
498 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
\r
499 Preference preference) {
\r
501 if (preference.getKey().equals(KEY_BUILD_VERSION)) {
\r
502 System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
\r
503 mHits[mHits.length - 1] = SystemClock.uptimeMillis();
\r
504 if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
\r
505 Toast ImageToast = new Toast(getBaseContext());
\r
506 LinearLayout toastLayout = new LinearLayout(
\r
508 toastLayout.setOrientation(LinearLayout.HORIZONTAL);
\r
509 ImageView image = new ImageView(getBaseContext());
\r
510 image.setImageResource(R.drawable.easter_egg);
\r
511 toastLayout.addView(image);
\r
512 ImageToast.setView(toastLayout);
\r
513 ImageToast.setDuration(Toast.LENGTH_SHORT);
\r
517 } catch (NullPointerException ee) {
\r
521 if (preference.getKey().equals(KEY_SOUND_EFFECT)) {
\r
522 Intent i = new Intent(
\r
523 AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
\r
525 i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION,
\r
526 MusicUtils.sService.getAudioSessionId());
\r
527 } catch (Exception e) {
\r
528 // TODO Auto-generated catch block
\r
529 e.printStackTrace();
\r
531 startActivityForResult(i, EFFECTS_PANEL);
\r
533 } catch (NullPointerException ee) {
\r
537 return super.onPreferenceTreeClick(preferenceScreen, preference);
\r