/*
* Copyright (C) 2013 Simon Vig Therkildsen
*
* 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 net.simonvt.cathode.ui;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Spinner;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import javax.inject.Inject;
import net.simonvt.cathode.CathodeApp;
import net.simonvt.cathode.HttpStatusCode;
import net.simonvt.cathode.IntPreference;
import net.simonvt.cathode.R;
import net.simonvt.cathode.api.TraktSettings;
import net.simonvt.cathode.api.util.TimeUtils;
import net.simonvt.cathode.event.AuthFailedEvent;
import net.simonvt.cathode.event.RequestFailedEvent;
import net.simonvt.cathode.event.SyncEvent;
import net.simonvt.cathode.event.SyncEvent.OnSyncListener;
import net.simonvt.cathode.jobqueue.AuthJobService;
import net.simonvt.cathode.jobqueue.Job;
import net.simonvt.cathode.jobqueue.JobListener;
import net.simonvt.cathode.jobqueue.JobManager;
import net.simonvt.cathode.jobqueue.JobService;
import net.simonvt.cathode.notification.NotificationService;
import net.simonvt.cathode.provider.DatabaseContract;
import net.simonvt.cathode.provider.DatabaseContract.ShowColumns;
import net.simonvt.cathode.provider.ProviderSchematic;
import net.simonvt.cathode.provider.ProviderSchematic.Shows;
import net.simonvt.cathode.provider.ShowDatabaseHelper;
import net.simonvt.cathode.remote.ForceUpdateJob;
import net.simonvt.cathode.remote.InitialSyncJob;
import net.simonvt.cathode.remote.sync.SyncWatching;
import net.simonvt.cathode.remote.sync.lists.SyncLists;
import net.simonvt.cathode.remote.sync.movies.StartSyncUpdatedMovies;
import net.simonvt.cathode.remote.sync.shows.StartSyncUpdatedShows;
import net.simonvt.cathode.settings.Settings;
import net.simonvt.cathode.settings.StartPage;
import net.simonvt.cathode.tmdb.api.SyncConfiguration;
import net.simonvt.cathode.util.DateUtils;
import okhttp3.logging.HttpLoggingInterceptor;
@SuppressLint("SetTextI18n") public abstract class BaseActivity extends AppCompatActivity {
private static final long FAKE_SHOW_ID = Long.MAX_VALUE;
final DebugViews debugViews = new DebugViews();
final DebugInjects injects = new DebugInjects();
private SharedPreferences settings;
@Override protected void onCreate(Bundle inState) {
super.onCreate(inState);
CathodeApp.inject(this);
CathodeApp.inject(this, injects);
super.setContentView(R.layout.debug_home);
settings = PreferenceManager.getDefaultSharedPreferences(this);
Context drawerContext = new ContextThemeWrapper(this, R.style.Theme_AppCompat);
LayoutInflater.from(drawerContext)
.inflate(R.layout.debug_drawer, (ViewGroup) ButterKnife.findById(this, R.id.debug_drawer));
ButterKnife.bind(debugViews, this);
SyncEvent.registerListener(debugSyncListener);
final StartPageAdapter startPageAdapter = new StartPageAdapter();
debugViews.startPage.setAdapter(startPageAdapter);
debugViews.startPage.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
StartPage startPage = startPageAdapter.getItem(position);
settings.edit().putString(Settings.START_PAGE, startPage.toString()).apply();
}
@Override public void onNothingSelected(AdapterView<?> parent) {
}
});
StartPage startPage =
StartPage.fromValue(settings.getString(Settings.START_PAGE, null), StartPage.DASHBOARD);
debugViews.startPage.setSelection(startPageAdapter.getPositionForValue(startPage));
debugViews.recreateActivity.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
recreate();
}
});
debugViews.updateNotifications.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
Intent i = new Intent(BaseActivity.this, NotificationService.class);
startService(i);
}
});
debugViews.requestFailedEvent.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
RequestFailedEvent.post(R.string.error_unknown_retrying);
debugViews.drawerLayout.closeDrawers();
}
});
debugViews.authFailedEvent.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
AuthFailedEvent.post();
debugViews.drawerLayout.closeDrawers();
}
});
debugViews.removeAccessToken.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
settings.edit().remove(Settings.TRAKT_ACCESS_TOKEN).apply();
}
});
debugViews.removeRefreshToken.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
settings.edit().remove(Settings.TRAKT_REFRESH_TOKEN).apply();
}
});
debugViews.invalidateAccessToken.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
settings.edit()
.putString(Settings.TRAKT_ACCESS_TOKEN, "invalid token")
.putLong(Settings.TRAKT_TOKEN_EXPIRATION, 0L)
.apply();
}
});
debugViews.invalidateRefreshToken.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
settings.edit().putString(Settings.TRAKT_REFRESH_TOKEN, "invalid token").apply();
}
});
debugViews.insertFakeShow.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
new Thread(new Runnable() {
@Override public void run() {
long showId = injects.showHelper.getId(FAKE_SHOW_ID);
if (showId > -1L) {
getContentResolver().delete(Shows.withId(showId), null, null);
}
ContentValues values = new ContentValues();
values.put(ShowColumns.TITLE, "Fake show");
values.put(ShowColumns.TRAKT_ID, FAKE_SHOW_ID);
values.put(ShowColumns.RUNTIME, 1);
Uri showUri = getContentResolver().insert(Shows.SHOWS, values);
showId = Shows.getShowId(showUri);
values = new ContentValues();
values.put(DatabaseContract.SeasonColumns.SHOW_ID, showId);
values.put(DatabaseContract.SeasonColumns.SEASON, 1);
Uri seasonUri = getContentResolver().insert(ProviderSchematic.Seasons.SEASONS, values);
long seasonId = ProviderSchematic.Seasons.getId(seasonUri);
long time = System.currentTimeMillis() - DateUtils.MINUTE_IN_MILLIS;
for (int i = 1; i <= 10; i++) {
values = new ContentValues();
values.put(DatabaseContract.EpisodeColumns.SHOW_ID, showId);
values.put(DatabaseContract.EpisodeColumns.SEASON_ID, seasonId);
values.put(DatabaseContract.EpisodeColumns.SEASON, 1);
values.put(DatabaseContract.EpisodeColumns.EPISODE, i);
values.put(DatabaseContract.EpisodeColumns.FIRST_AIRED, time);
values.put(DatabaseContract.EpisodeColumns.WATCHED, i == 1);
getContentResolver().insert(ProviderSchematic.Episodes.EPISODES, values);
time += DateUtils.MINUTE_IN_MILLIS;
}
}
}).start();
}
});
debugViews.removeFakeShow.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
final long showId = injects.showHelper.getId(FAKE_SHOW_ID);
if (showId > -1L) {
getContentResolver().delete(Shows.withId(showId), null, null);
}
}
});
final EnumAdapter<HttpLoggingInterceptor.Level> logLevelAdapter =
new EnumAdapter(HttpLoggingInterceptor.Level.values());
debugViews.logLevel.setAdapter(logLevelAdapter);
debugViews.logLevel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
HttpLoggingInterceptor.Level logLevel = logLevelAdapter.getItem(position);
injects.loggingInterceptor.setLevel(logLevel);
}
@Override public void onNothingSelected(AdapterView<?> adapterView) {
}
});
debugViews.logLevel.setSelection(
logLevelAdapter.getPositionForValue(injects.loggingInterceptor.getLevel()));
int[] statusCodes = new int[] {
200, 401, 404, 409, 412, 502,
};
final IntAdapter httpStatusCodeAdapter = new IntAdapter(statusCodes);
debugViews.httpStatusCode.setAdapter(httpStatusCodeAdapter);
debugViews.httpStatusCode.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
injects.httpStatusCodePreference.set(httpStatusCodeAdapter.getItem(position));
}
@Override public void onNothingSelected(AdapterView<?> parent) {
}
});
debugViews.httpStatusCode.setSelection(
httpStatusCodeAdapter.getPositionForValue(injects.httpStatusCodePreference.get()));
debugViews.syncConfiguration.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
injects.jobManager.addJob(new SyncConfiguration());
}
});
debugViews.initialSync.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
injects.jobManager.addJob(new InitialSyncJob());
}
});
debugViews.forceUpdate.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
injects.jobManager.addJob(new ForceUpdateJob());
}
});
debugViews.updatedLastDay.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
String lastUpdated = TimeUtils.getIsoTime();
settings.edit()
.putString(Settings.MOVIES_LAST_UPDATED, lastUpdated)
.putString(Settings.SHOWS_LAST_UPDATED, lastUpdated)
.apply();
injects.jobManager.addJob(new StartSyncUpdatedShows());
injects.jobManager.addJob(new StartSyncUpdatedMovies());
}
});
debugViews.syncWatching.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
injects.jobManager.addJob(new SyncWatching());
}
});
debugViews.syncLists.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
injects.jobManager.addJob(new SyncLists());
}
});
injects.jobManager.addJobListener(jobListener);
debugViews.startJobService.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
Intent i = new Intent(BaseActivity.this, JobService.class);
startService(i);
i = new Intent(BaseActivity.this, AuthJobService.class);
startService(i);
}
});
}
private JobListener jobListener = new JobListener() {
@Override public void onJobsLoaded(JobManager jobManager) {
debugViews.jobCount.setText(String.valueOf(jobManager.jobCount()));
}
@Override public void onJobAdded(JobManager jobManager, Job job) {
debugViews.jobCount.setText(String.valueOf(jobManager.jobCount()));
}
@Override public void onJobRemoved(JobManager jobManager, Job job) {
debugViews.jobCount.setText(String.valueOf(jobManager.jobCount()));
}
};
@Override public void setContentView(int layoutResID) {
debugViews.container.removeAllViews();
getLayoutInflater().inflate(layoutResID, debugViews.container);
}
@Override protected void onDestroy() {
injects.jobManager.removeJobListener(jobListener);
SyncEvent.unregisterListener(debugSyncListener);
super.onDestroy();
}
private OnSyncListener debugSyncListener = new OnSyncListener() {
@Override public void onSyncChanged(int authSyncCount, int jobSyncCount) {
if (authSyncCount > 0) {
debugViews.authJobServiceStatus.setText("Running");
} else {
debugViews.authJobServiceStatus.setText("Stopped");
}
if (jobSyncCount > 0) {
debugViews.jobServiceStatus.setText("Running");
} else {
debugViews.jobServiceStatus.setText("Stopped");
}
}
};
public static class DebugInjects {
@Inject @HttpStatusCode IntPreference httpStatusCodePreference;
@Inject JobManager jobManager;
@Inject TraktSettings traktSettings;
@Inject HttpLoggingInterceptor loggingInterceptor;
@Inject ShowDatabaseHelper showHelper;
}
static class DebugViews {
@BindView(R.id.debug_drawerLayout) DrawerLayout drawerLayout;
@BindView(R.id.debug_content) ViewGroup container;
@BindView(R.id.debug_startPage) Spinner startPage;
@BindView(R.id.debug_recreateActivity) View recreateActivity;
@BindView(R.id.debug_updateNotifications) View updateNotifications;
@BindView(R.id.debug_requestFailedEvent) View requestFailedEvent;
@BindView(R.id.debug_authFailedEvent) View authFailedEvent;
@BindView(R.id.debug_removeAccessToken) View removeAccessToken;
@BindView(R.id.debug_removeRefreshToken) View removeRefreshToken;
@BindView(R.id.debug_invalidateAccessToken) View invalidateAccessToken;
@BindView(R.id.debug_invalidateRefreshToken) View invalidateRefreshToken;
@BindView(R.id.debug_insertFakeShow) View insertFakeShow;
@BindView(R.id.debug_removeFakeShow) View removeFakeShow;
@BindView(R.id.debug_logLevel) Spinner logLevel;
@BindView(R.id.debug_networkStatusCode) Spinner httpStatusCode;
@BindView(R.id.debug_drawer) ViewGroup drawerContent;
@BindView(R.id.debug_syncConfiguration) View syncConfiguration;
@BindView(R.id.debug_initialSync) View initialSync;
@BindView(R.id.debug_forceUpdate) View forceUpdate;
@BindView(R.id.debug_updatedLastDay) View updatedLastDay;
@BindView(R.id.debug_syncWatching) View syncWatching;
@BindView(R.id.debug_syncLists) View syncLists;
@BindView(R.id.debug_authJobServiceStatus) TextView authJobServiceStatus;
@BindView(R.id.debug_jobServiceStatus) TextView jobServiceStatus;
@BindView(R.id.debug_jobCount) TextView jobCount;
@BindView(R.id.debug_startJobService) TextView startJobService;
}
}