/* * Copyright 2013 Dmitry Monakhov. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package monakhv.android.samlib.service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.*; import android.support.annotation.Nullable; import in.srain.cube.views.ptr.util.PrefsUtil; import monakhv.android.samlib.R; import monakhv.android.samlib.data.SettingsHelper; import monakhv.samlib.db.entity.Author; import monakhv.samlib.db.entity.SamLibConfig; import monakhv.samlib.log.Log; import monakhv.samlib.service.*; import rx.Subscription; import java.util.Calendar; /** * Bind Service to checkout Authors Updates * Created by monakhv on 23.11.15. */ public class UpdateLocalService extends MyService { private static final String DEBUG_TAG = "UpdateLocalService"; public static final String PREF_NAME = "monakhv.android.samlib.service.UpdateLocalService"; public static final String PREF_KEY_LAST_UPDATE = PREF_NAME + ".LAST_UPDATE"; private static final String PREF_KEY_CALLER = PREF_NAME + ".CALLER"; static final String ACTION_STOP = "UpdateLocalService.ACTION_STOP"; private static final String ACTION_UPDATE = "UpdateLocalService.ACTION_UPDATE"; private static final String EXTRA_ARGUMENT = "UpdateLocalService.EXTRA_ARGUMENT"; private final IBinder mBinder = new LocalBinder(); private SharedPreferences mSharedPreferences; private MessageConstructor mMessageConstructor; private static boolean isRun = false; private boolean isReceiver = false; private static PowerManager.WakeLock wl; private static Thread mThread; public UpdateLocalService() { super(); // Log.d(DEBUG_TAG, "Constructor Call"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); Log.i(DEBUG_TAG, "OnStart"); if (action.equalsIgnoreCase(ACTION_STOP)) { Log.i(DEBUG_TAG, "OnStart: making stop: is Run " + isRun); interrupt(); stopSelf(); } if (action.equalsIgnoreCase(ACTION_UPDATE)) { Log.i(DEBUG_TAG, "OnStart: making update"); ArgumentData arg = intent.getExtras().getParcelable(EXTRA_ARGUMENT); if (arg != null) { isReceiver = arg.isReceiver == 1; } runService(arg); } return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } /** * Method to start update process * * @param context Context * @param author Author can be null, if not null - check the author for updates * @param state Author GUI state to make gui update, contains tagId to update authors by the tag */ public static void makeUpdate(Context context, Author author, AuthorGuiState state) { Intent service = new Intent(context, UpdateLocalService.class); service.setAction(UpdateLocalService.ACTION_UPDATE); ArgumentData argumentData; if (author == null) { argumentData = new ArgumentData(state); } else { argumentData = new ArgumentData(author, state); } service.putExtra(UpdateLocalService.EXTRA_ARGUMENT, argumentData); context.startService(service); } private void runService(ArgumentData argData) { if (isRun) { Log.i(DEBUG_TAG, "runService: Update already running exiting"); return; } mSharedPreferences = PrefsUtil.getSharedPreferences(this, PREF_NAME); getSettingsHelper().requestFirstBackup(); mSharedPreferences.edit().putBoolean(PREF_KEY_CALLER, isReceiver).apply(); if (isReceiver && !getSettingsHelper().haveInternetWIFI()) { monakhv.samlib.log.Log.d(DEBUG_TAG, "runService: Ignore update task - we have no internet connection"); return; } if (!SettingsHelper.haveInternet(this)) { Log.e(DEBUG_TAG, "runService: Ignore update - we have no internet connection"); return; } String title; if (argData.author_id == -1) { switch (argData.state_id){ case SamLibConfig.TAG_AUTHOR_ALL: title = getString(R.string.notification_title_TAG_ALL) ; break; case SamLibConfig.TAG_AUTHOR_NEW: title = getString(R.string.notification_title_TAG_NEW); break; default: title = getString(R.string.notification_title_TAG) + " " + getAuthorController().getTagController().getById(argData.state_id).getName(); } } else { title = getAuthorController().getById(argData.author_id).getName(); } PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DEBUG_TAG); wl.acquire(); SpecialAuthorService service = getSpecialSamlibService(); mThread = new SamlibUpdateTread(service, argData); final Subscription subscription = getBus().getObservable() .distinctUntilChanged() .subscribe(guiUpdateObject -> { if (guiUpdateObject.isProgress()) { if (mMessageConstructor == null) { mMessageConstructor = new MessageConstructor(this, getSettingsHelper()); } mMessageConstructor.updateNotification((AuthorUpdateProgress) guiUpdateObject.getObject(), title); Log.d(DEBUG_TAG, "runService: progressUpdate"); } if (guiUpdateObject.isResult()) { mMessageConstructor.cancelProgress(); mMessageConstructor.showUpdateNotification((Result) guiUpdateObject.getObject()); Log.d(DEBUG_TAG, "runService: Result"); } if (guiUpdateObject.isAuthor() && guiUpdateObject.getUpdateType() == GuiUpdateObject.UpdateType.UPDATE_UPDATE) { Author author = (Author) guiUpdateObject.getObject(); mMessageConstructor.updateNotification(author); Log.d(DEBUG_TAG, "runService: AuthorUpdate: " + author.getName()); } }); addSubscription(subscription); mThread.start(); } /** * Interrupt the thread if running */ private void interrupt() { if (mMessageConstructor != null) { mMessageConstructor.cancelProgress(); } if (isRun) { Log.d(DEBUG_TAG, "Making STOP"); mThread.interrupt(); getHttpClientController().cancelAll(); // UpdateLocalService.this.mSamlibApplication.releaseServiceComponent(); releaseLock(); } } public boolean isRunning() { return isRun; } public class LocalBinder extends Binder { public UpdateLocalService getService() { return UpdateLocalService.this; } } private class SamlibUpdateTread extends Thread { final private AuthorUpdateService mAuthorUpdateService; final private ArgumentData mData; SamlibUpdateTread(AuthorUpdateService authorUpdateService, ArgumentData data) { mAuthorUpdateService = authorUpdateService; mData = data; } @Override public void run() { super.run(); isRun = true; boolean result; if (mData.author_id == -1) { result = mAuthorUpdateService.runUpdateService(mData.getState()); } else { Author author = getAuthorController().getById(mData.author_id); result = mAuthorUpdateService.runUpdateService(author, mData.getState()); } if (result) { if (getSettingsHelper().getLimitBookLifeTimeFlag() && isReceiver) { CleanBookServiceIntent.start(UpdateLocalService.this); } mSharedPreferences.edit().putLong(PREF_KEY_LAST_UPDATE, Calendar.getInstance().getTime().getTime()).apply(); } isRun = false; releaseLock(); UpdateLocalService.this.stopSelf(); } } /** * Release power lock */ private void releaseLock() { if (wl.isHeld()) { wl.release(); } } private static class ArgumentData implements Parcelable { int state_id; String order; int author_id = -1; int isReceiver; /** * For update all authors by the tag * * @param state Gui state contains tag id */ ArgumentData(AuthorGuiState state) { state_id = state.getSelectedTagId(); order = state.getSorOrder(); if (order == null) { isReceiver = 1; } else { isReceiver = 0; } } /** * The constructor is used for check update for the single author * Call only from Activity * * @param author Author to update * @param state GUI state */ ArgumentData(Author author, AuthorGuiState state) { this(state); author_id = author.getId(); isReceiver = 0; } AuthorGuiState getState() { return new AuthorGuiState(state_id, order); } ArgumentData(Parcel in) { state_id = in.readInt(); order = in.readString(); author_id = in.readInt(); isReceiver = in.readInt(); } public static final Creator<ArgumentData> CREATOR = new Creator<ArgumentData>() { @Override public ArgumentData createFromParcel(Parcel in) { return new ArgumentData(in); } @Override public ArgumentData[] newArray(int size) { return new ArgumentData[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(state_id); dest.writeString(order); dest.writeInt(author_id); dest.writeInt(isReceiver); } } }