Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 100: Add a settings menu with a single preference for controlling sync frequency. #103

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CREDITS.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ the alternative [Git logo](http://henrik.nyh.se/2007/06/alternative-git-logo-and

* Bernd Hirschler - [German Translation](https://github.com/rtyley/agit/pull/35)

* Scott Johnson - [Sync Frequency UI](https://github.com/rtyley/agit/pull/103)

* Eddie Ringle - [Tweak GitHub url parsing](https://github.com/rtyley/agit/pull/29)

* Leonardo Taglialegne - [Italian Translation](https://github.com/rtyley/agit/pull/46)
Expand Down
13 changes: 13 additions & 0 deletions agit/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
</intent-filter>
</activity>

<activity android:name="SettingsActivity">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

<activity android:name=".AboutUsingSshActivity">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
Expand Down Expand Up @@ -142,6 +148,12 @@
</intent-filter>
</activity>

<receiver android:name=".sync.SyncRepoManager" android:exported="true">
<intent-filter>
<action android:name="com.madgag.agit.sync.SET_DAILY_SYNC" />
</intent-filter>
</receiver>

<service android:name="GitOperationsService">
<intent-filter>
<action android:name="org.openintents.git.repo.SYNC"/>
Expand Down Expand Up @@ -184,4 +196,5 @@
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.READ_SYNC_STATS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
</manifest>
18 changes: 18 additions & 0 deletions agit/res/layout/settings_activity.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/settings">

<PreferenceCategory
android:title="@string/settings_category_sync">
<ListPreference
android:id="@+id/setting_sync_frequency_listPref"
android:key="@string/setting_sync_frequency_key"
android:title="@string/setting_title_sync_frequency"
android:summary="@string/setting_instruction_sync_frequency"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The summary text shown to the user on the 'Settings' screen should actually tell them what the schedule is, so they don't have to tap through to see what it is. Ie 'Every Hour' (PocketCast again):

screenshot_2014-03-15-22-36-07

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this now to perform this action. It's included in the most recent diff.

android:entries="@array/setting_sync_choices"
android:entryValues="@array/setting_sync_choices_values"
android:dialogTitle="@string/setting_title_sync_frequency">
</ListPreference>
</PreferenceCategory>
</PreferenceScreen>
5 changes: 5 additions & 0 deletions agit/res/menu/dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
android:title="@string/open_menu_option"
android:showAsAction="never">
</item>
<item
android:id="@+id/settings"
android:showAsAction="never"
android:title="@string/settings_app_menu_option">
</item>
<item
android:id="@+id/about_app"
android:showAsAction="never"
Expand Down
43 changes: 43 additions & 0 deletions agit/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<string name="using_ssh_activity_title">SSH Install Guide</string>
<string name="clone_launcher_activity_title">Clone...</string>
<string name="clone_menu_option">Clone...</string>
<string name="settings_app_menu_option">Settings...</string>
<string name="enter_clone_url">Url</string>
<string name="clone_target_folder_label">Target Folder</string>
<string name="clone_url_hint">Repository url</string>
Expand Down Expand Up @@ -112,4 +113,46 @@

<string name="no_viewer_available_for_file">"No viewer available for '%1$s'"</string>

<!-- Settings Strings -->
<string name="settings">Settings</string>
<string name="settings_category_sync">Sync Settings</string>
<string name="setting_title_sync_frequency">Sync Frequency</string>
<string name="setting_instruction_sync_frequency">Tap to set how often repository synchronization will occur</string>
<string name="setting_sync_frequency_key">setting_sync_frequency</string>

<string name="setting_sync_frequency_daily">0</string>
<string name="setting_sync_frequency_daily_title">Sync daily at</string>
<string name="setting_sync_frequency_daily_hour_key">setting_sync_frequency_daily_hour</string>
<string name="setting_sync_frequency_daily_min_key">setting_sync_frequency_daily_min</string>
<string name="setting_sync_frequency_subtitle_key">setting_sync_frequency_subtitle</string>

<!--
These next two arrays need to be in sync (no pun intended). In other words, if you change
setting_sync_choices to have another value, you need to put a corresponding integer value
into the setting_sync_choices_values
-->
<string-array name="setting_sync_choices">
<item>Manually</item>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should apologise here, as I should have specified in my comment #103 (comment) that while I thought the screenshot represented a reasonable look-and-feel (ie using a restricted set of options in a list box), the preferred list of options was actually mentioned in #103 (comment), ie the list would be this:

  • Manually
  • Schedule daily at... (I'm in two minds about this, but on balance, fair enough)
  • Every minute
  • Every 5 minutes
  • Every 15 minutes
  • Every hour
  • Every 4 hours
  • Every day
  • Every week

I wasn't actually anticipating you implementing the 'Schedule daily at...' functionality, and initially I was going to ask you to take it out, because I wasn't sure it was worth the extra code and requirement for an additional permission. I'm still rather ambivalent about it, but if you think it's worth having, then it can stay in...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now updated the list of sync possibilities to include the options (and only those options) that you specify in this list.

I wasn't actually anticipating you implementing the 'Schedule daily at...' functionality, and initially I was going to ask you to take it out, because I wasn't sure it was worth the extra code and requirement for an additional permission. I'm still rather ambivalent about it, but if you think it's worth having, then it can stay in...

Oh, my mistake. I didn't realize you weren't thinking this would go into the change. I actually think this is the one I'll use most frequently. I use agit quite frequently for updating my configuration repository. Since it's on my phone, I can then just pull updated configuration files off of my phone onto another machine when doing sysadmin tasks (e.g. if it doesn't have internet access for some reason, I can use my phone as a USB drive quite easily).

Since I do update these configuration files remotely, but not very often, I thought it would be nice if it sync'ed every night. However, since there are a lot of them, I'd like to sync every night when I'm sleeping (and thus not using my phone). :)

On the other hand, I can totally see that the added permission is not ideal. It's up to you - I'd be fine taking it out if you would rather not incur the cost of the app permission.

<item>Schedule daily at&#8230;</item>
<item>Every minute</item>
<item>Every 5 minutes</item>
<item>Every 15 minutes</item>
<item>Every hour</item>
<item>Every 4 hours</item>
<item>Every day</item>
<item>Every week</item>
</string-array>

<!-- These next values are in MINUTES (except for the special values for "Manually" and "Sync Daily" -->
<string-array name="setting_sync_choices_values">
<item>-1</item>
<item>@string/setting_sync_frequency_daily</item>
<item>1</item>
<item>5</item>
<item>15</item>
<item>60</item>
<item>240</item>
<item>1440</item>
<item>10080</item>
</string-array>
</resources>
4 changes: 3 additions & 1 deletion agit/src/main/java/com/madgag/agit/DashboardActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.github.rtyley.android.sherlock.roboguice.activity.RoboSherlockFragmentActivity;
import com.madgag.android.IntentUtil;
import com.madgag.android.util.store.InstallAppDialogFragment;

import java.io.File;
Expand Down Expand Up @@ -81,6 +80,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
case R.id.clone:
startActivity(new Intent(this, CloneLauncherActivity.class));
return true;
case R.id.settings:
startActivity(new Intent(this, SettingsActivity.class));
return true;
case R.id.open_repo:
if (isIntentAvailable(this, PICK_DIRECTORY_INTENT)) {
Intent intent = new Intent(PICK_DIRECTORY_INTENT);
Expand Down
127 changes: 127 additions & 0 deletions agit/src/main/java/com/madgag/agit/SettingsActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2011, 2012 Roberto Tyley
*
* This file is part of 'Agit' - an Android Git client.
*
* Agit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Agit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/ .
*/

package com.madgag.agit;

import static com.madgag.agit.sync.AccountAuthenticatorService.addAccount;
import android.app.TimePickerDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.TimePicker;

import com.madgag.agit.sync.SyncRepoManager;

public class SettingsActivity extends PreferenceActivity {
public void onCreate(Bundle aSavedInstanceState) {
super.onCreate(aSavedInstanceState);
addPreferencesFromResource(R.layout.settings_activity);
ListPreference syncFreq = (ListPreference) findPreference(getString(R.string.setting_sync_frequency_key));
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsActivity.this);
setSummary();
syncFreq.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
String value = (String)o;
final SharedPreferences.Editor edtr = prefs.edit();

if (value.equals(getString(R.string.setting_sync_frequency_daily))) {
// Check if our previous value was the same thing, so we can set it in the time
// picker dialog.
int hourDefault = 12;
int minDefault = 0;
String prevVal = prefs.getString(getString(R.string.setting_sync_frequency_key), "-1");
if (prevVal.equals(o)) {
hourDefault = prefs.getInt(getString(R.string.setting_sync_frequency_daily_hour_key), hourDefault);
minDefault = prefs.getInt(getString(R.string.setting_sync_frequency_daily_min_key), minDefault);
}

TimePickerDialog.OnTimeSetListener timeListener = new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker timePicker, int hourOfDay, int minOfHour) {
String subTitle = "Sync daily at " + hourOfDay + ":" + (minOfHour < 10 ? "0" : "") + minOfHour;
edtr.putInt(getString(R.string.setting_sync_frequency_daily_hour_key), hourOfDay);
edtr.putInt(getString(R.string.setting_sync_frequency_daily_min_key), minOfHour);
edtr.putString(getString(R.string.setting_sync_frequency_subtitle_key), subTitle);
edtr.commit();

SyncRepoManager manager = new SyncRepoManager();
manager.setDailySync(SettingsActivity.this, hourOfDay, minOfHour);
SettingsActivity.this.setSummary();
}
};

// Display new dialog with the available options.
TimePickerDialog timePicker = new TimePickerDialog(SettingsActivity.this, timeListener, hourDefault, minDefault, false);
timePicker.setTitle(getString(R.string.setting_sync_frequency_daily_title));
timePicker.show();
} else {
// Loop to find out what the index of the chosen value is in the array - it should be the same
// as the chosen value in the array of possible choices (see comment in strings.xml).
String[] indexArray = getResources().getStringArray(R.array.setting_sync_choices_values);
String[] subtitleArray = getResources().getStringArray(R.array.setting_sync_choices);
int subtitleIndex = 0;
for (String s : indexArray) {
if (s.equals(o)) {
break;
}
subtitleIndex++;
}

String subTitle = subtitleArray[subtitleIndex];
edtr.putString(getString(R.string.setting_sync_frequency_subtitle_key), subTitle);
edtr.commit();
SyncRepoManager manager = new SyncRepoManager();
manager.cancelDailySync(SettingsActivity.this);
}

SettingsActivity.this.setSummary();

return true;
}
});
}

@Override
public void onDestroy() {
super.onDestroy();
try {
addAccount(this);
} catch (Exception e) {
Log.w(TAG, "Unable to re-add account for syncing after preference changes", e);
}
}

/**
* Displays the value stored in the preference setting_sync_frequency_subtitle_key in the summary line of the
* list preference, so the user doesn't have to click through to view which option is selected.
*/
private void setSummary() {
ListPreference syncFreq = (ListPreference) findPreference(getString(R.string.setting_sync_frequency_key));
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsActivity.this);
syncFreq.setSummary(prefs.getString(getString(R.string.setting_sync_frequency_subtitle_key),
getString(R.string.setting_instruction_sync_frequency)));
}

private static final String TAG = "SettingsActivity";
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;

/**
Expand Down Expand Up @@ -71,15 +73,28 @@ public static Bundle addAccount(Context ctx) {
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
}
configureSyncFor(account);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
int syncFreq = Integer.parseInt(prefs.getString("setting_sync_frequency", "-1"));
configureSyncFor(account, syncFreq);

return result;
}

private static void configureSyncFor(Account account) {
Log.d(TAG, "Trying to configure account for sync...");
setIsSyncable(account, AGIT_PROVIDER_AUTHORITY, 1);
setSyncAutomatically(account, AGIT_PROVIDER_AUTHORITY, true);
ContentResolver.addPeriodicSync(account, AGIT_PROVIDER_AUTHORITY, new Bundle(), (long) (15 * 60));
private static void configureSyncFor(Account aAccount, int aSyncFreq) {
// There are three possible sync settings we could have:
// < 0: Indicates sync is disabled
// == 0: Indicates sync is enabled, but it's handled by an alarm because it's a time-of-day sync
// > 0: Indicates sync should be enabled for aSyncFreq minutes
if (aSyncFreq < 0) {
Log.d(TAG, "Disabling sync settings");
setIsSyncable(aAccount, AGIT_PROVIDER_AUTHORITY, 0);
ContentResolver.removePeriodicSync(aAccount, AGIT_PROVIDER_AUTHORITY, new Bundle());
} else {
Log.d(TAG, "Trying to configure account for sync at rate of " + aSyncFreq + " minutes");
setIsSyncable(aAccount, AGIT_PROVIDER_AUTHORITY, 1);
setSyncAutomatically(aAccount, AGIT_PROVIDER_AUTHORITY, true);
ContentResolver.addPeriodicSync(aAccount, AGIT_PROVIDER_AUTHORITY, new Bundle(), (long) (aSyncFreq * 60));
}
}

private static class AccountAuthenticatorImpl extends AbstractAccountAuthenticator {
Expand Down
2 changes: 2 additions & 0 deletions agit/src/main/java/com/madgag/agit/sync/SyncAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import android.content.Context;
import android.content.SyncResult;
import android.os.Bundle;
import android.util.Log;

import com.google.inject.Inject;
import com.google.inject.Singleton;
Expand All @@ -50,6 +51,7 @@ public SyncAdapter(Context context) {
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
SyncResult syncResult) {
Log.d(TAG, "Performing sync");
cancelAnyCurrentCampaign();
contextScope.enter(getContext());
try {
Expand Down
Loading