package com.zegoggles.smssync.service;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.PowerManager;
import android.provider.Telephony;
import android.util.Log;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.BinaryTempFileBody;
import com.squareup.otto.Produce;
import com.squareup.otto.Subscribe;
import com.zegoggles.smssync.App;
import com.zegoggles.smssync.R;
import com.zegoggles.smssync.auth.OAuth2Client;
import com.zegoggles.smssync.auth.TokenRefresher;
import com.zegoggles.smssync.contacts.ContactAccessor;
import com.zegoggles.smssync.mail.MessageConverter;
import com.zegoggles.smssync.mail.PersonLookup;
import com.zegoggles.smssync.preferences.AuthPreferences;
import com.zegoggles.smssync.service.exception.SmsProviderNotWritableException;
import com.zegoggles.smssync.service.state.RestoreState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FilenameFilter;
import static com.zegoggles.smssync.App.LOCAL_LOGV;
import static com.zegoggles.smssync.App.TAG;
import static com.zegoggles.smssync.mail.DataType.CALLLOG;
import static com.zegoggles.smssync.mail.DataType.SMS;
import static com.zegoggles.smssync.service.state.SmsSyncState.ERROR;
public class SmsRestoreService extends ServiceBase {
private static final int RESTORE_ID = 2;
@NotNull private RestoreState mState = new RestoreState();
@Nullable private static SmsRestoreService service;
@Override @NotNull
public RestoreState getState() {
return mState;
}
@Override
public void onCreate() {
super.onCreate();
asyncClearCache();
BinaryTempFileBody.setTempDirectory(getCacheDir());
service = this;
}
@Override
public void onDestroy() {
super.onDestroy();
if (LOCAL_LOGV) Log.v(TAG, "SmsRestoreService#onDestroy(state"+getState()+")");
service = null;
}
/**
* Android KitKat and above require SMS Backup+ to be the default SMS application in order to
* write to the SMS Provider.
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private boolean canWriteToSmsProvider() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ||
getPackageName().equals(Telephony.Sms.getDefaultSmsPackage(this));
}
@Override
protected void handleIntent(final Intent intent) {
if (isWorking()) return;
try {
final boolean restoreCallLog = CALLLOG.isRestoreEnabled(service);
final boolean restoreSms = SMS.isRestoreEnabled(service);
if (restoreSms && !canWriteToSmsProvider()) {
postError(new SmsProviderNotWritableException());
return;
}
MessageConverter converter = new MessageConverter(service,
getPreferences(),
getAuthPreferences().getUserEmail(),
new PersonLookup(getContentResolver()),
ContactAccessor.Get.instance()
);
RestoreConfig config = new RestoreConfig(
getBackupImapStore(),
0,
restoreSms,
restoreCallLog,
getPreferences().isRestoreStarredOnly(),
getPreferences().getMaxItemsPerRestore(),
0
);
final AuthPreferences authPreferences = new AuthPreferences(this);
new RestoreTask(this, converter, getContentResolver(),
new TokenRefresher(service, new OAuth2Client(authPreferences.getOAuth2ClientId()), authPreferences)).execute(config);
} catch (MessagingException e) {
postError(e);
}
}
private void postError(Exception exception) {
App.bus.post(mState.transition(ERROR, exception));
}
private void asyncClearCache() {
new Thread("clearCache") {
@Override
public void run() {
clearCache();
}
}.start();
}
public synchronized void clearCache() {
File tmp = getCacheDir();
if (tmp == null) return; // not sure why this would return null
Log.d(TAG, "clearing cache in " + tmp);
for (File f : tmp.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("body");
}
})) {
if (LOCAL_LOGV) Log.v(TAG, "deleting " + f);
if (!f.delete()) Log.w(TAG, "error deleting " + f);
}
}
@Subscribe public void restoreStateChanged(final RestoreState state) {
mState = state;
if (mState.isInitialState()) return;
if (mState.isRunning()) {
notification = createNotification(R.string.status_restore)
.setContentTitle(getString(R.string.status_restore))
.setContentText(state.getNotificationLabel(getResources()))
.setContentIntent(getPendingIntent())
.getNotification();
startForeground(RESTORE_ID, notification);
} else {
Log.d(TAG, "stopping service, state"+mState);
stopForeground(true);
stopSelf();
}
}
@Produce public RestoreState produceLastState() {
return mState;
}
@Override protected int wakeLockType() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// hold a full wake lock when restoring on newer version of Android, since
// the user needs to switch back the sms app afterwards
return PowerManager.FULL_WAKE_LOCK;
} else {
return super.wakeLockType();
}
}
public static boolean isServiceWorking() {
return service != null && service.isWorking();
}
}