diff --git a/app/build.gradle b/app/build.gradle index 17f73686..d2da05b7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,6 +82,7 @@ dependencies { compile 'com.github.ksoichiro:android-observablescrollview:1.5.1' compile 'asia.ivity.android:drag-sort-listview:1.0' compile 'de.hdodenhof:circleimageview:1.3.0' + compile "com.github.semoncat.seekarc:library:0.1" compile 'com.squareup.retrofit:retrofit:1.9.0' compile 'com.squareup.okhttp:okhttp:2.4.0' diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java new file mode 100644 index 00000000..094c23f0 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java @@ -0,0 +1,175 @@ +package com.kabouzeid.gramophone.dialogs; + +import android.app.AlarmManager; +import android.app.Dialog; +import android.app.PendingIntent; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.widget.FrameLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.service.MusicService; +import com.kabouzeid.gramophone.util.MusicUtil; +import com.kabouzeid.gramophone.util.PreferenceUtils; +import com.triggertrap.seekarc.SeekArc; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class SleepTimerDialog extends DialogFragment { + @InjectView(R.id.seek_arc) + SeekArc seekArc; + @InjectView(R.id.timer_display) + TextView timerDisplay; + + private int seekArcProgress; + private MaterialDialog materialDialog; + private TimerUpdater timerUpdater; + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + timerUpdater.cancel(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + timerUpdater = new TimerUpdater(); + materialDialog = new MaterialDialog.Builder(getActivity()) + .title(getActivity().getResources().getString(R.string.action_sleep_timer)) + .positiveText(R.string.action_set) + .callback(new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + if (getActivity() == null) { + return; + } + final int min = seekArcProgress; + PreferenceUtils.getInstance(getActivity()).setLastSleepTimerValue(min); + + PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT); + + final long nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + min * 60 * 1000; + PreferenceUtils.getInstance(getActivity()).setNextSleepTimerElapsedRealtime(nextSleepTimerElapsedTime); + AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi); + + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_set, min), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onNeutral(MaterialDialog dialog) { + if (getActivity() == null) { + return; + } + final PendingIntent previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE); + if (previous != null) { + AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + am.cancel(previous); + previous.cancel(); + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show(); + } + } + }) + .showListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + if (makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) != null) { + timerUpdater.start(); + } + } + }) + .customView(R.layout.dialog_sleep_timer, false) + .build(); + + if (getActivity() == null || materialDialog.getCustomView() == null) { + return materialDialog; + } + + ButterKnife.inject(this, materialDialog.getCustomView()); + + seekArc.post(new Runnable() { + @Override + public void run() { + int width = seekArc.getWidth(); + int height = seekArc.getHeight(); + int small = Math.min(width, height); + + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(seekArc.getLayoutParams()); + layoutParams.height = small; + seekArc.setLayoutParams(layoutParams); + } + }); + + seekArcProgress = PreferenceUtils.getInstance(getActivity()).getLastSleepTimerValue(); + updateTimeDisplayTime(); + seekArc.setProgress(seekArcProgress); + + seekArc.setOnSeekArcChangeListener(new SeekArc.OnSeekArcChangeListener() { + @Override + public void onProgressChanged(SeekArc seekArc, int i, boolean b) { + if (i < 1) { + seekArc.setProgress(1); + return; + } + seekArcProgress = i; + updateTimeDisplayTime(); + } + + @Override + public void onStartTrackingTouch(SeekArc seekArc) { + + } + + @Override + public void onStopTrackingTouch(SeekArc seekArc) { + + } + }); + + return materialDialog; + } + + private void updateTimeDisplayTime() { + timerDisplay.setText(seekArcProgress + " min"); + } + + private PendingIntent makeTimerPendingIntent(int flag) { + return PendingIntent.getService(getActivity(), 0, makeTimerIntent(), flag); + } + + private Intent makeTimerIntent() { + return new Intent(getActivity(), MusicService.class) + .setAction(MusicService.ACTION_QUIT); + } + + private class TimerUpdater extends CountDownTimer { + public TimerUpdater() { + super(PreferenceUtils.getInstance(getActivity()).getNextSleepTimerElapsedRealTime() - SystemClock.elapsedRealtime(), 1000); + } + + @Override + public void onTick(long millisUntilFinished) { + materialDialog.setActionButton(DialogAction.NEUTRAL, materialDialog.getContext().getString(R.string.cancel_current_timer) + " (" + MusicUtil.getReadableDurationString(millisUntilFinished) + ")"); + } + + @Override + public void onFinish() { + materialDialog.setActionButton(DialogAction.NEUTRAL, null); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/loader/LastAddedLoader.java b/app/src/main/java/com/kabouzeid/gramophone/loader/LastAddedLoader.java index 2359ba53..0b0838c2 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/loader/LastAddedLoader.java +++ b/app/src/main/java/com/kabouzeid/gramophone/loader/LastAddedLoader.java @@ -20,7 +20,7 @@ public class LastAddedLoader { public static Cursor makeLastAddedCursor(final Context context) { long fourWeeksAgo = (System.currentTimeMillis() / 1000) - (4 * 3600 * 24 * 7); // possible saved timestamp caused by user "clearing" the last added playlist - long cutoff = PreferenceUtils.getInstance(context).getLastAddedCutOff() / 1000; + long cutoff = PreferenceUtils.getInstance(context).getLastAddedCutOffTimestamp() / 1000; if (cutoff < fourWeeksAgo) { cutoff = fourWeeksAgo; } diff --git a/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java b/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java index 3006a8fc..ad3b84cd 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java +++ b/app/src/main/java/com/kabouzeid/gramophone/service/MultiPlayer.java @@ -210,6 +210,9 @@ public class MultiPlayer implements MediaPlayer.OnErrorListener, * @return The duration in milliseconds */ public int duration() { + if (!mIsInitialized) { + return -1; + } try { return mCurrentMediaPlayer.getDuration(); } catch (IllegalStateException e) { @@ -223,6 +226,9 @@ public class MultiPlayer implements MediaPlayer.OnErrorListener, * @return The current position in milliseconds */ public int position() { + if (!mIsInitialized) { + return -1; + } try { return mCurrentMediaPlayer.getCurrentPosition(); } catch (IllegalStateException e) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java index 0390555e..048f8325 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/AlbumDetailActivity.java @@ -27,6 +27,7 @@ import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.songadapter.AlbumSongAdapter; +import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager; import com.kabouzeid.gramophone.interfaces.CabHolder; @@ -347,6 +348,9 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER"); + return true; case R.id.action_equalizer: NavigationUtil.openEqualizer(this); return true; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java index d0d9811a..d853fa25 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/ArtistDetailActivity.java @@ -33,6 +33,7 @@ import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.ArtistAlbumAdapter; import com.kabouzeid.gramophone.adapter.songadapter.ArtistSongAdapter; +import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.bitmapblur.StackBlurManager; import com.kabouzeid.gramophone.interfaces.CabHolder; @@ -449,6 +450,9 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER"); + return true; case R.id.action_equalizer: NavigationUtil.openEqualizer(this); return true; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java index 481db105..36b1b470 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java @@ -37,6 +37,7 @@ import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.PagerAdapter; import com.kabouzeid.gramophone.dialogs.AboutDialog; import com.kabouzeid.gramophone.dialogs.CreatePlaylistDialog; +import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.helper.SearchQueryHelper; import com.kabouzeid.gramophone.interfaces.CabHolder; @@ -338,6 +339,9 @@ public class MainActivity extends AbsFabActivity int id = item.getItemId(); switch (id) { + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER"); + return true; case R.id.action_equalizer: NavigationUtil.openEqualizer(this); return true; diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java index 15d71f22..5bddc584 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java @@ -37,6 +37,7 @@ import com.afollestad.materialdialogs.ThemeSingleton; import com.afollestad.materialdialogs.util.DialogUtils; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; +import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; import com.kabouzeid.gramophone.dialogs.SongDetailDialog; import com.kabouzeid.gramophone.dialogs.SongShareDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; @@ -629,6 +630,9 @@ public class MusicControllerActivity extends AbsFabActivity { public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER"); + return true; case R.id.action_toggle_favorite: MusicUtil.toggleFavorite(this, song); if (MusicUtil.isFavorite(this, song)) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java index b99371f1..972d0b80 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PlaylistDetailActivity.java @@ -14,6 +14,7 @@ import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.adapter.songadapter.AbsPlaylistSongAdapter; import com.kabouzeid.gramophone.adapter.songadapter.PlaylistSongAdapter; +import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.misc.DragSortRecycler; @@ -124,6 +125,9 @@ public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { + case R.id.action_sleep_timer: + new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER"); + return true; case R.id.action_shuffle_playlist: //noinspection unchecked MusicPlayerRemote.openAndShuffleQueue(this, adapter.getDataSet(), true); diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java index 2808cb35..8dc7bfd1 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtils.java @@ -44,6 +44,8 @@ public final class PreferenceUtils { public static final String GAPLESS_PLAYBACK = "gapless_playback"; public static final String LAST_ADDED_CUTOFF_TIMESTAMP = "last_added_cutoff_timestamp"; public static final String ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen"; + public static final String LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value"; + public static final String NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time"; private static PreferenceUtils sInstance; @@ -285,7 +287,7 @@ public final class PreferenceUtils { return mPreferences.getInt(ALBUM_GRID_COLUMNS_LAND, 3); } - public long getLastAddedCutOff() { + public long getLastAddedCutOffTimestamp() { return mPreferences.getLong(LAST_ADDED_CUTOFF_TIMESTAMP, 0L); } @@ -295,4 +297,24 @@ public final class PreferenceUtils { editor.putLong(LAST_ADDED_CUTOFF_TIMESTAMP, timestamp); editor.commit(); } + + public int getLastSleepTimerValue() { + return mPreferences.getInt(LAST_SLEEP_TIMER_VALUE, 30); + } + + public void setLastSleepTimerValue(final int value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(LAST_SLEEP_TIMER_VALUE, value); + editor.apply(); + } + + public long getNextSleepTimerElapsedRealTime() { + return mPreferences.getLong(NEXT_SLEEP_TIMER_ELAPSED_REALTIME, -1); + } + + public void setNextSleepTimerElapsedRealtime(final long value) { + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putLong(NEXT_SLEEP_TIMER_ELAPSED_REALTIME, value); + editor.apply(); + } } diff --git a/app/src/main/res/drawable-xhdpi/default_album_art.png b/app/src/main/res/drawable-xhdpi/default_album_art.png deleted file mode 100644 index 1647dde0..00000000 Binary files a/app/src/main/res/drawable-xhdpi/default_album_art.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/default_album_art.png b/app/src/main/res/drawable-xxxhdpi/default_album_art.png new file mode 100644 index 00000000..baef1699 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/default_album_art.png differ diff --git a/app/src/main/res/drawable/traditional_slider_thumb_dark.xml b/app/src/main/res/drawable/traditional_slider_thumb_dark.xml new file mode 100644 index 00000000..943b1d3b --- /dev/null +++ b/app/src/main/res/drawable/traditional_slider_thumb_dark.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_sleep_timer.xml b/app/src/main/res/layout/dialog_sleep_timer.xml new file mode 100644 index 00000000..75fe00c8 --- /dev/null +++ b/app/src/main/res/layout/dialog_sleep_timer.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/app/src/main/res/menu/menu_album_detail.xml b/app/src/main/res/menu/menu_album_detail.xml index 3f96a1f5..25fedb3c 100644 --- a/app/src/main/res/menu/menu_album_detail.xml +++ b/app/src/main/res/menu/menu_album_detail.xml @@ -1,13 +1,13 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:context="com.kabouzeid.gramophone.ui.activities.AlbumDetailActivity"> + app:showAsAction="ifRoom" /> + app:showAsAction="never" /> + app:showAsAction="never" /> + app:showAsAction="never" /> + + + app:showAsAction="never" /> diff --git a/app/src/main/res/menu/menu_albums.xml b/app/src/main/res/menu/menu_albums.xml index c25091c0..ed69f97a 100644 --- a/app/src/main/res/menu/menu_albums.xml +++ b/app/src/main/res/menu/menu_albums.xml @@ -1,7 +1,7 @@ - - + + + + + + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:context=".DrawerActivity"> + app:showAsAction="always" /> + app:showAsAction="ifRoom" /> + + + app:showAsAction="never" /> + android:id="@+id/action_sleep_timer" + android:title="@string/action_sleep_timer" + app:showAsAction="never" /> + app:showAsAction="never" /> diff --git a/app/src/main/res/menu/menu_music_playing.xml b/app/src/main/res/menu/menu_music_playing.xml index 83c92e17..82a33555 100644 --- a/app/src/main/res/menu/menu_music_playing.xml +++ b/app/src/main/res/menu/menu_music_playing.xml @@ -3,16 +3,16 @@ xmlns:tools="http://schemas.android.com/tools" tools:context="com.kabouzeid.gramophone.ui.activities.MusicControllerActivity"> - + + + - diff --git a/app/src/main/res/menu/menu_playlist_detail.xml b/app/src/main/res/menu/menu_playlist_detail.xml index aafc15b4..79431da1 100644 --- a/app/src/main/res/menu/menu_playlist_detail.xml +++ b/app/src/main/res/menu/menu_playlist_detail.xml @@ -20,6 +20,11 @@ android:title="@string/action_shuffle_playlist" app:showAsAction="never" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 00d53799..a0769766 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,7 +4,7 @@ Currently listening to %1$s by %2$s The Audio File Do you want to set %1$s as your ringtone? - %1$s has been set as your ringtone. + %1$s has been set as your ringtone Set as Ringtone Share "Settings" @@ -28,8 +28,8 @@ Songs Playlists Nothing is playing - An error occurred while attempting to play this song. - We were not able to find a matching biography for this artist. + An error occurred while attempting to play this song + Could not find a matching biography for this artist Biography No audio focus. Tag Editor @@ -40,7 +40,7 @@ Year Track "Track (2 for track 2 or 3004 for CD3 track 4)" - The album title or the album artist text field is empty. + The album title or the album artist text field is empty Writing file Saving changes… Details @@ -62,13 +62,13 @@ Updated artist image. Could not update artist image. Updating… - "Added 1 title to the playing queue." - Added %1$d titles to the playing queue. + "Added 1 title to the playing queue" + Added %1$d titles to the playing queue Remove from playlist New playlist… Grid columns Grid columns (Land) - Inserted %1$d songs into this playlist. + Inserted %1$d songs into this playlist Created playlist %1$s Deleted playlist %1$s Deleted %1$d songs @@ -90,7 +90,7 @@ Clear Playlist "Add to Playlist" New Playlist - "Warning: This operation can not be undone." + "Warning: This operation can not be undone" Shuffle All Shuffle Album Shuffle Artist @@ -171,4 +171,9 @@ Download from Last.fm Pick from Local Storage Web Search + Sleep timer + Set + Cancel current timer + Sleep timer has been canceled + Sleep timer set for %d minutes from now diff --git a/app/src/main/res/values/styles_parents.xml b/app/src/main/res/values/styles_parents.xml index 3ad3ae5b..3423b1a1 100644 --- a/app/src/main/res/values/styles_parents.xml +++ b/app/src/main/res/values/styles_parents.xml @@ -20,6 +20,7 @@ @drawable/round_selector_dark @drawable/rect_selector_dark @color/materialmusic_dark_separator_color + @drawable/traditional_slider_thumb_dark @color/materialmusic_dark_themed_drawable_color @color/grey_900 @@ -52,6 +53,7 @@ @drawable/round_selector @drawable/rect_selector @color/materialmusic_separator_color + @drawable/traditional_slider_thumb @color/materialmusic_themed_drawable_color @color/white diff --git a/build.gradle b/build.gradle index 7bbd3f39..b936ade6 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.0-beta1' + classpath 'com.android.tools.build:gradle:1.3.0-beta4' } }