diff --git a/app/build.gradle b/app/build.gradle index 5ab820972..ed1938ab7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,6 @@ android { targetSdkVersion 25 versionCode 5 versionName "1.0.5" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -21,17 +20,11 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support:design:25.3.1' compile 'com.android.support:support-v4:25.3.1' - compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4' compile 'com.loopj.android:android-async-http:1.4.9' compile 'com.google.code.gson:gson:2.8.0' - compile 'com.squareup.retrofit2:retrofit:2.2.0' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' - compile 'com.evernote:android-job:1.1.9' - testCompile 'junit:junit:4.12' + compile 'com.evernote:android-job:1.1.10' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8cc184ac3..eb839a2ac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,7 +66,6 @@ . */ package fr.gouv.etalab.mastodon.activities; +import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Color; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.Html; import android.text.method.LinkMovementMethod; import android.view.MenuItem; +import android.view.View; +import android.widget.Button; import android.widget.TextView; import mastodon.etalab.gouv.fr.mastodon.R; @@ -48,24 +52,34 @@ public class AboutActivity extends AppCompatActivity { about_version.setText(getResources().getString(R.string.about_vesrion, version)); } catch (PackageManager.NameNotFoundException ignored) {} - TextView about_developer = (TextView) findViewById(R.id.about_developer); - TextView about_license = (TextView) findViewById(R.id.about_license); - TextView about_code = (TextView) findViewById(R.id.about_code); - about_developer.setMovementMethod(LinkMovementMethod.getInstance()); - about_license.setMovementMethod(LinkMovementMethod.getInstance()); - about_code.setMovementMethod(LinkMovementMethod.getInstance()); - about_developer.setLinkTextColor(Color.BLUE); - about_license.setLinkTextColor(Color.BLUE); - about_code.setLinkTextColor(Color.BLUE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - about_developer.setText(Html.fromHtml(getString(R.string.about_developer), Html.FROM_HTML_MODE_COMPACT)); - about_license.setText(Html.fromHtml(getString(R.string.about_license), Html.FROM_HTML_MODE_COMPACT)); - about_code.setText(Html.fromHtml(getString(R.string.about_code), Html.FROM_HTML_MODE_COMPACT)); - }else { - about_developer.setText(Html.fromHtml(getString(R.string.about_developer))); - about_license.setText(Html.fromHtml(getString(R.string.about_license))); - about_code.setText(Html.fromHtml(getString(R.string.about_code))); - } + Button about_developer = (Button) findViewById(R.id.about_developer); + Button about_code = (Button) findViewById(R.id.about_code); + Button about_license = (Button) findViewById(R.id.about_license); + + about_code.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://bitbucket.org/tom79/mastodon_etalab")); + startActivity(browserIntent); + } + }); + about_developer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(AboutActivity.this, ShowAccountActivity.class); + Bundle b = new Bundle(); + b.putString("accountId", "2416"); + intent.putExtras(b); + startActivity(intent); + } + }); + about_license.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.gnu.org/licenses/quick-guide-gplv3.fr.html")); + startActivity(browserIntent); + } + }); } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java index 3a79eee0a..a6e35b8ee 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainActivity.java @@ -62,8 +62,9 @@ import fr.gouv.etalab.mastodon.fragments.TabLayoutSettingsFragment; import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import mastodon.etalab.gouv.fr.mastodon.R; +import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT; import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION; -import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_NOTIFICATION; +import static fr.gouv.etalab.mastodon.helper.Helper.NOTIFICATION_INTENT; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, OnUpdateAccountInfoInterface { @@ -138,10 +139,14 @@ public class MainActivity extends AppCompatActivity boolean menuWasSelected = false; if( getIntent() != null && getIntent().getExtras() != null ){ Bundle extras = getIntent().getExtras(); - if (extras.getInt(INTENT_ACTION) == INTENT_NOTIFICATION){ + if (extras.getInt(INTENT_ACTION) == NOTIFICATION_INTENT){ navigationView.setCheckedItem(R.id.nav_notification); navigationView.getMenu().performIdentifierAction(R.id.nav_notification, 0); menuWasSelected = true; + }else if( extras.getInt(INTENT_ACTION) == HOME_TIMELINE_INTENT){ + navigationView.setCheckedItem(R.id.nav_home); + navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0); + menuWasSelected = true; } } if (savedInstanceState == null && !menuWasSelected) { @@ -190,10 +195,13 @@ public class MainActivity extends AppCompatActivity return; Bundle extras = intent.getExtras(); if( extras.containsKey(INTENT_ACTION) ){ - if (extras.getInt(INTENT_ACTION) == INTENT_NOTIFICATION){ - final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); + final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); + if (extras.getInt(INTENT_ACTION) == NOTIFICATION_INTENT){ navigationView.setCheckedItem(R.id.nav_notification); navigationView.getMenu().performIdentifierAction(R.id.nav_notification, 0); + }else if( extras.getInt(INTENT_ACTION) == HOME_TIMELINE_INTENT){ + navigationView.setCheckedItem(R.id.nav_home); + navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0); } } intent.replaceExtras(new Bundle()); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java index 3ed2bfe00..f35014176 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/MainApplication.java @@ -18,10 +18,12 @@ import android.app.Application; import com.evernote.android.job.JobManager; import fr.gouv.etalab.mastodon.jobs.ApplicationJob; +import fr.gouv.etalab.mastodon.jobs.HomeTimelineSyncJob; import fr.gouv.etalab.mastodon.jobs.NotificationsSyncJob; /** * Created by Thomas on 29/04/2017. + * Main application, jobs are launched here. */ public class MainApplication extends Application{ @@ -32,6 +34,7 @@ public class MainApplication extends Application{ super.onCreate(); JobManager.create(this).addJobCreator(new ApplicationJob()); JobManager.instance().getConfig().setVerbose(false); - NotificationsSyncJob.schedule(getApplicationContext(), false); + NotificationsSyncJob.schedule(false); + HomeTimelineSyncJob.schedule(false); } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java index bd3998e29..d32d47c6a 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java @@ -17,6 +17,7 @@ package fr.gouv.etalab.mastodon.activities; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; @@ -25,6 +26,7 @@ import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; +import android.text.Html; import android.view.MenuItem; import android.view.View; import android.widget.Button; @@ -206,7 +208,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi TextView account_dn = (TextView) findViewById(R.id.account_dn); TextView account_un = (TextView) findViewById(R.id.account_un); TextView account_ac = (TextView) findViewById(R.id.account_ac); - + TextView account_note = (TextView) findViewById(R.id.account_note); if( account != null){ setTitle(account.getAcct()); account_dn.setText(account.getDisplay_name()); @@ -215,9 +217,14 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi account_ac.setVisibility(View.GONE); else account_ac.setText(account.getAcct()); - tabLayout.getTabAt(0).setText(getString(R.string.status) + "\n" + String.valueOf(account.getStatuses_count())); - tabLayout.getTabAt(1).setText(getString(R.string.following) + "\n" + String.valueOf(account.getFollowing_count())); - tabLayout.getTabAt(2).setText(getString(R.string.followers) + "\n" + String.valueOf(account.getFollowers_count())); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + account_note.setText(Html.fromHtml(account.getNote(), Html.FROM_HTML_MODE_COMPACT)); + else + //noinspection deprecation + account_note.setText(Html.fromHtml(account.getNote())); + tabLayout.getTabAt(0).setText(getString(R.string.status_cnt, account.getStatuses_count())); + tabLayout.getTabAt(1).setText(getString(R.string.following_cnt, account.getFollowing_count())); + tabLayout.getTabAt(2).setText(getString(R.string.followers_cnt, account.getFollowers_count())); imageLoader.displayImage(account.getAvatar(), account_pp, options); } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveHomeTimelineServiceAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveHomeTimelineServiceAsyncTask.java new file mode 100644 index 000000000..1abc000f3 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveHomeTimelineServiceAsyncTask.java @@ -0,0 +1,57 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastodon Etalab for mastodon.etalab.gouv.fr + * + * This program 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. + * + * Mastodon Etalab 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 Thomas Schneider; if not, + * see . */ +package fr.gouv.etalab.mastodon.asynctasks; + +import android.content.Context; +import android.os.AsyncTask; + +import java.util.List; + +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveHomeTimelineServiceInterface; + +/** + * Created by Thomas on 20/05/2017. + * Retrieves home timeline for the authenticated user - used in the service + */ + +public class RetrieveHomeTimelineServiceAsyncTask extends AsyncTask { + + private Context context; + private List statuses; + private String since_id; + private String acct; + private OnRetrieveHomeTimelineServiceInterface listener; + + + public RetrieveHomeTimelineServiceAsyncTask(Context context, String since_id, String acct, OnRetrieveHomeTimelineServiceInterface onRetrieveHomeTimelineServiceInterface){ + this.context = context; + this.since_id = since_id; + this.listener = onRetrieveHomeTimelineServiceInterface; + this.acct = acct; + } + + @Override + protected Void doInBackground(Void... params) { + statuses = new API(context).getHomeTimelineSinceId(since_id); + return null; + } + + @Override + protected void onPostExecute(Void result) { + listener.onRetrieveHomeTimelineService(statuses, acct); + } + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index 7960929d2..9fd6a2e54 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -296,13 +296,7 @@ public class API { return statusContext; } - /** - * Retrieves home timeline for the account *synchronously* - * @return List - */ - public List getHomeTimeline() { - return getHomeTimeline(null, null, tootPerPage); - } + /** * Retrieves home timeline for the account *synchronously* @@ -313,6 +307,14 @@ public class API { return getHomeTimeline(max_id, null, tootPerPage); } + /** + * Retrieves home timeline for the account since an id *synchronously* + * @return List + */ + public List getHomeTimelineSinceId(String since_id) { + return getHomeTimeline(null, since_id, tootPerPage); + } + /** * Retrieves home timeline for the account *synchronously* * @param max_id String id max diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index c3ad89c7f..3b9ee37c7 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -19,14 +19,20 @@ package fr.gouv.etalab.mastodon.helper; import android.app.AlertDialog; import android.app.DownloadManager; +import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.media.RingtoneManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.os.Environment; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; import android.view.WindowManager; import android.widget.Toast; @@ -38,9 +44,12 @@ import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import fr.gouv.etalab.mastodon.activities.MainActivity; import mastodon.etalab.gouv.fr.mastodon.R; import fr.gouv.etalab.mastodon.client.API; +import static android.app.Notification.DEFAULT_SOUND; +import static android.app.Notification.DEFAULT_VIBRATE; import static android.content.Context.DOWNLOAD_SERVICE; @@ -77,10 +86,10 @@ public class Helper { public static final String SCOPES = "scopes"; public static final String WEBSITE = "website"; public static final String LAST_NOTIFICATION_MAX_ID = "last_notification_max_id"; - + public static final String LAST_HOMETIMELINE_MAX_ID = "last_hometimeline_max_id"; //Notifications - public static final String NOTIFICATION_TYPE = "notification_type"; public static final int NOTIFICATION_INTENT = 1; + public static final int HOME_TIMELINE_INTENT = 2; //Settings public static final String SET_TOOTS_PER_PAGE = "set_toots_per_page"; @@ -108,10 +117,10 @@ public class Helper { //Refresh job public static final int MINUTES_BETWEEN_NOTIFICATIONS_REFRESH = 15; + public static final int MINUTES_BETWEEN_HOME_TIMELINE = 30; //Intent public static final String INTENT_ACTION = "intent_action"; - public static final int INTENT_NOTIFICATION = 1; //Receiver public static final String SEARCH_VALIDATE_ACCOUNT = "search_validate_account"; @@ -365,4 +374,40 @@ public class Helper { alert.show(); } + + /** + * Sends notification with intent + * @param context Context + * @param intentAction int intent action + * @param notificationId int id of the notification + * @param icon Bitmap profile picture + * @param title String title of the notification + * @param message String message for the notification + */ + public static void notify_user(Context context, int intentAction, int notificationId, Bitmap icon, String title, String message ) { + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + // prepare intent which is triggered if the user click on the notification + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + final Intent intent = new Intent(context, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); + intent.putExtra(INTENT_ACTION, intentAction); + PendingIntent pIntent = PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_ONE_SHOT); + RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + // build notification + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context) + .setSmallIcon(R.drawable.notification_icon) + .setTicker(message) + .setWhen(System.currentTimeMillis()) + .setAutoCancel(true) + .setContentIntent(pIntent) + .setContentText(message); + if( sharedpreferences.getBoolean(Helper.SET_NOTIF_SILENT,false) ) { + notificationBuilder.setDefaults(DEFAULT_VIBRATE); + }else { + notificationBuilder.setDefaults(DEFAULT_SOUND); + } + notificationBuilder.setContentTitle(title); + notificationBuilder.setLargeIcon(icon); + notificationManager.notify(notificationId, notificationBuilder.build()); + } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveHomeTimelineServiceInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveHomeTimelineServiceInterface.java new file mode 100644 index 000000000..4ac7f3fe2 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveHomeTimelineServiceInterface.java @@ -0,0 +1,27 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastodon Etalab for mastodon.etalab.gouv.fr + * + * This program 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. + * + * Mastodon Etalab 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 Thomas Schneider; if not, + * see . */ +package fr.gouv.etalab.mastodon.interfaces; + + +import java.util.List; +import fr.gouv.etalab.mastodon.client.Entities.Status; + +/** + * Created by Thomas on 20/05/2017. + * Interface when home timeline toots have been retrieved + */ +public interface OnRetrieveHomeTimelineServiceInterface { + void onRetrieveHomeTimelineService(List statuses, String acct); +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java index 84c301cc3..31be81763 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/ApplicationJob.java @@ -28,6 +28,8 @@ public class ApplicationJob implements JobCreator { switch (tag) { case NotificationsSyncJob.NOTIFICATION_REFRESH: return new NotificationsSyncJob(); + case HomeTimelineSyncJob.HOME_TIMELINE: + return new HomeTimelineSyncJob(); default: return null; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java new file mode 100644 index 000000000..215e2f1de --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java @@ -0,0 +1,162 @@ +package fr.gouv.etalab.mastodon.jobs; +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastodon Etalab for mastodon.etalab.gouv.fr + * + * This program 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. + * + * Mastodon Etalab 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 Thomas Schneider; if not, + * see . */ + +import android.content.Context; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.support.annotation.NonNull; + +import com.evernote.android.job.Job; +import com.evernote.android.job.JobManager; +import com.evernote.android.job.JobRequest; +import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; + +import java.io.File; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import fr.gouv.etalab.mastodon.asynctasks.RetrieveHomeTimelineServiceAsyncTask; +import fr.gouv.etalab.mastodon.client.Entities.Account; +import fr.gouv.etalab.mastodon.client.Entities.Status; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveHomeTimelineServiceInterface; +import fr.gouv.etalab.mastodon.sqlite.AccountDAO; +import fr.gouv.etalab.mastodon.sqlite.Sqlite; +import mastodon.etalab.gouv.fr.mastodon.R; + +import static fr.gouv.etalab.mastodon.helper.Helper.HOME_TIMELINE_INTENT; +import static fr.gouv.etalab.mastodon.helper.Helper.notify_user; + + +/** + * Created by Thomas on 20/05/2017. + * Notifications for home timeline job + */ + +public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineServiceInterface{ + + static final String HOME_TIMELINE = "home_timeline"; + private int notificationId; + + @NonNull + @Override + protected Result onRunJob(Params params) { + callAsynchronousTask(); + return Result.SUCCESS; + } + + + public static int schedule(boolean updateCurrent){ + + Set jobRequests = JobManager.instance().getAllJobRequestsForTag(HOME_TIMELINE); + if (!jobRequests.isEmpty() && !updateCurrent) { + return jobRequests.iterator().next().getJobId(); + } + return new JobRequest.Builder(HomeTimelineSyncJob.HOME_TIMELINE) + .setPeriodic(TimeUnit.MINUTES.toMillis(Helper.MINUTES_BETWEEN_HOME_TIMELINE), TimeUnit.MINUTES.toMillis(5)) + .setPersisted(true) + .setUpdateCurrent(updateCurrent) + .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) + .setRequirementsEnforced(false) + .build() + .schedule(); + } + + + /** + * Task in background starts here. + */ + private void callAsynchronousTask() { + final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true); + //User disagree with home timeline refresh + if( !notif_hometimeline) + return; //Nothing is done + SQLiteDatabase db = Sqlite.getInstance(getContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + //If an Internet connection and user agrees with notification refresh + //If WIFI only and on WIFI OR user defined any connections to use the service. + if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getContext())) { + List accounts = new AccountDAO(getContext(),db).getAllAccount(); + //It means there is no user in DB. + if( accounts == null ) + return; + //Retrieve users in db that owner has. + for (Account account: accounts) { + String since_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + account.getAcct(), null); + notificationId = (int) Math.round(Double.parseDouble(account.getId())/1000); + new RetrieveHomeTimelineServiceAsyncTask(getContext(), since_id, account.getAcct(), HomeTimelineSyncJob.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + } + } + } + + + @Override + public void onRetrieveHomeTimelineService(List statuses, String acct) { + if( statuses == null || statuses.size() == 0) + return; + Bitmap icon_notification = null; + final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + + String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + acct, null); + //No previous notifications in cache, so no notification will be sent + if( max_id != null ){ + String message; + String title = null; + for(Status status: statuses){ + //The notification associated to max_id is discarded as it is supposed to have already been sent + if( status.getId().equals(max_id)) + continue; + String notificationUrl = status.getAccount().getAvatar(); + if( notificationUrl != null && icon_notification == null){ + try { + ImageLoader imageLoaderNoty = ImageLoader.getInstance(); + File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name)); + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext()) + .threadPoolSize(5) + .threadPriority(Thread.MIN_PRIORITY + 3) + .denyCacheImageMultipleSizesInMemory() + .diskCache(new UnlimitedDiskCache(cacheDir)) + .build(); + imageLoaderNoty.init(config); + icon_notification = imageLoaderNoty.loadImageSync(notificationUrl); + title = getContext().getResources().getString(R.string.notif_pouet, status.getAccount().getDisplay_name()); + }catch (Exception e){ + icon_notification = BitmapFactory.decodeResource(getContext().getResources(), + R.drawable.mastodon_logo); + } + } + } + if(statuses.size() > 0 ) + message = getContext().getResources().getQuantityString(R.plurals.other_notif_hometimeline, statuses.size(), statuses.size()); + else + message = ""; + notify_user(getContext(), HOME_TIMELINE_INTENT, notificationId, icon_notification,title,message); + } + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + acct, statuses.get(0).getId()); + editor.apply(); + } + + + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java index 35e2df73d..2f2ab6cb4 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java @@ -13,18 +13,15 @@ package fr.gouv.etalab.mastodon.jobs; * * You should have received a copy of the GNU General Public License along with Thomas Schneider; if not, * see . */ -import android.app.PendingIntent; + import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.media.RingtoneManager; import android.os.AsyncTask; import android.support.annotation.NonNull; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; + import com.evernote.android.job.Job; import com.evernote.android.job.JobManager; @@ -39,7 +36,6 @@ import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; -import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.helper.Helper; import mastodon.etalab.gouv.fr.mastodon.R; import fr.gouv.etalab.mastodon.asynctasks.RetrieveNotificationsAsyncTask; @@ -49,8 +45,8 @@ import fr.gouv.etalab.mastodon.interfaces.OnRetrieveNotificationsInterface; import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import fr.gouv.etalab.mastodon.sqlite.Sqlite; -import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION; -import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_NOTIFICATION; +import static fr.gouv.etalab.mastodon.helper.Helper.NOTIFICATION_INTENT; +import static fr.gouv.etalab.mastodon.helper.Helper.notify_user; /** @@ -60,8 +56,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_NOTIFICATION; public class NotificationsSyncJob extends Job implements OnRetrieveNotificationsInterface{ - public static final String NOTIFICATION_REFRESH = "job_notification"; - private int jobId; + static final String NOTIFICATION_REFRESH = "job_notification"; private int notificationId; @NonNull @@ -73,7 +68,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications } - public static int schedule(Context context, boolean updateCurrent){ + public static int schedule(boolean updateCurrent){ Set jobRequests = JobManager.instance().getAllJobRequestsForTag(NOTIFICATION_REFRESH); if (!jobRequests.isEmpty() && !updateCurrent) { @@ -99,6 +94,15 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications SQLiteDatabase db = Sqlite.getInstance(getContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); //If an Internet connection and user agrees with notification refresh final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + //Check which notifications the user wants to see + boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); + boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); + boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true); + boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); + boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); + //User disagree with all notifications + if( !notif_follow && !notif_add && !notif_ask && !notif_mention && !notif_share) + return; //Nothing is done //If WIFI only and on WIFI OR user defined any connections to use the service. if(!sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false) || Helper.isOnWIFI(getContext())) { List accounts = new AccountDAO(getContext(),db).getAllAccount(); @@ -124,7 +128,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true); boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true); - boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true); + //boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true); boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true); boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true); String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + acct, null); @@ -137,7 +141,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications int newShare = 0; String notificationUrl = null; String title = null; - String message = null; + String message; for(Notification notification: notifications){ //The notification associated to max_id is discarded as it is supposed to have already been sent if( notification.getId().equals(max_id)) @@ -207,7 +211,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications message = getContext().getResources().getQuantityString(R.plurals.other_notifications, other, other); else message = ""; - notify_user(icon_notification,title,message); + notify_user(getContext(), NOTIFICATION_INTENT, notificationId, icon_notification,title,message); } } SharedPreferences.Editor editor = sharedpreferences.edit(); @@ -216,36 +220,4 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications } - /** - * Sends notification with intent - * @param icon Bitmap profile picture - * @param title String title of the notification - * @param message String message for the notification - */ - private void notify_user(Bitmap icon, String title, String message ) { - final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - // prepare intent which is triggered if the user click on the notification - NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getContext()); - final Intent intent = new Intent(getContext(), MainActivity.class); - intent.putExtra(Helper.NOTIFICATION_TYPE, Helper.NOTIFICATION_INTENT); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); - intent.putExtra(INTENT_ACTION, INTENT_NOTIFICATION); - PendingIntent pIntent = PendingIntent.getActivity(getContext(), notificationId, intent, PendingIntent.FLAG_ONE_SHOT); - - RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - // build notification - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getContext()) - .setSmallIcon(R.drawable.notification_icon) - .setTicker(message) - .setWhen(System.currentTimeMillis()) - .setAutoCancel(true) - .setContentIntent(pIntent) - .setContentText(message); - if( !sharedpreferences.getBoolean(Helper.SET_NOTIF_SILENT,false) ) { - notificationBuilder.setDefaults(-1); - } - notificationBuilder.setContentTitle(title); - notificationBuilder.setLargeIcon(icon); - notificationManager.notify(notificationId, notificationBuilder.build()); - } } diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index f94e777b9..6990bbf42 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -20,6 +20,7 @@ android:layout_height="match_parent" android:orientation="vertical" > + + - + - + +