blob: 425cce595cc52f9542d218c6fd0c04c1d5ccd09d [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* 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 com.android.sync;
import android.app.Activity;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.database.Cursor;
import android.database.DatabaseUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class Sync extends Activity {
private static final String TAG = "SyncPanel";
// TODO: move this to a centralized place?
private static final String SYNC_CONNECTION_SETTING_CHANGED
= "com.android.sync.SYNC_CONN_STATUS_CHANGED";
private static final int SYNC_BUTTON = 1;
private static final int CANCEL_BUTTON = 2;
private Button mSyncButton;
private Button mAdvancedButton;
private LinearLayout mAdvancedSection;
private Button mHistoryButton;
private TextView mAccountTextView;
private TextView mStatusView;
private TextView mMoreStatusView;
private CheckBox mListenForTicklesCheckBox;
private Spinner mContentNameSpinner;
private CheckBox mSyncProviderOnTickleCheckBox;
private List mProviderNames;
private List mProviderInfos;
private HashMap<String, Boolean> mProvidersToTickle = null;
android.provider.Sync.Settings.QueryMap mSyncSettings;
private OnClickListener mStartSync = new OnClickListener() {
public void onClick(View v) {
doSync();
}
};
private OnClickListener mCancelSync = new OnClickListener() {
public void onClick(View v) {
mStatusView.setText("Cancelled");
setSyncButton(SYNC_BUTTON);
getContentResolver().cancelSync(null /* cancel any sync */);
}
};
private OnClickListener mToggleListenForTickles = new OnClickListener() {
public void onClick(View v) {
boolean oldListenForTickles = mSyncSettings.getListenForNetworkTickles();
boolean listenForTickles = mListenForTicklesCheckBox.isChecked();
if (oldListenForTickles != listenForTickles) {
mSyncSettings.setListenForNetworkTickles(listenForTickles);
Intent intent = new Intent();
intent.setAction(SYNC_CONNECTION_SETTING_CHANGED);
sendBroadcast(intent);
}
}
};
private AdapterView.OnItemSelectedListener mContentNameListener =
new AdapterView.OnItemSelectedListener() {
public void onItemSelected(
AdapterView parent, View v,
int position,
long id) {
updateProviderUi();
}
public void onNothingSelected(AdapterView parent) {
// TODO: when does this happen? What does it mean?
}
};
private OnClickListener mToggleSyncOnTickle = new OnClickListener() {
public void onClick(View v) {
String providerName = getSelectedProviderName();
boolean syncOnTickle =
mSyncProviderOnTickleCheckBox.isChecked();
ContentResolver cr = getContentResolver();
boolean oldShouldSyncOnTickle =
mSyncSettings.getSyncProviderAutomatically(providerName);
if (syncOnTickle != oldShouldSyncOnTickle) {
mSyncSettings.setSyncProviderAutomatically(providerName, syncOnTickle);
updateCachedSettingsAndProviderUi();
}
}
};
private android.provider.Sync.Active.QueryMap mActiveSyncQueryMap;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();
// init views
setContentView(R.layout.sync_screen);
mAccountTextView = (TextView) findViewById(R.id.account);
mStatusView = (TextView) findViewById(R.id.status);
mMoreStatusView = (TextView) findViewById(R.id.moreStatus);
mSyncButton = (Button) findViewById(R.id.sync);
mAdvancedButton = (Button) findViewById(R.id.advanced);
mAdvancedSection = (LinearLayout) findViewById(R.id.advancedSection);
mAdvancedSection.setVisibility(View.INVISIBLE);
mAdvancedButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
int visibility = mAdvancedSection.getVisibility();
mAdvancedSection.setVisibility(visibility == View.INVISIBLE ?
View.VISIBLE : View.INVISIBLE);
}});
mHistoryButton = (Button) mAdvancedSection.findViewById(R.id.history);
mHistoryButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_RUN);
intent.setClass(Sync.this, SyncHistory.class);
intent.putExtra("authority", getSelectedProviderName());
startActivity(intent);
}});
final ContentResolver contentResolver = getContentResolver();
mSyncSettings = new android.provider.Sync.Settings.QueryMap(contentResolver,
true /* keep updated */, null);
mSyncSettings.addObserver(new Observer() {
public void update(Observable o, Object arg) {
updateCachedSettingsAndProviderUi();
}
});
mActiveSyncQueryMap = new android.provider.Sync.Active.QueryMap(getContentResolver(),
false /* don't keep updated, we will change this in onResume()/onPause() */,
null /* use this thread's handler for notifications */);
mActiveSyncQueryMap.addObserver(mSyncObserver);
mProviderNames = new ArrayList();
mProviderInfos = new ArrayList();
try {
ActivityThread.getPackageManager().querySyncProviders(mProviderNames,
mProviderInfos);
} catch (RemoteException e) {
}
mProviderNames.add(0, "All");
mProviderInfos.add(0, null);
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, mProviderNames);
adapter.setDropDownViewResource(
android.R.layout.simple_dropdown_item_1line);
mContentNameSpinner = (Spinner) findViewById(R.id.contentName);
mContentNameSpinner.setAdapter(adapter);
mContentNameSpinner.setOnItemSelectedListener(mContentNameListener);
mListenForTicklesCheckBox =
(CheckBox) findViewById(R.id.listenForTickles);
mListenForTicklesCheckBox.setOnClickListener(mToggleListenForTickles);
mSyncProviderOnTickleCheckBox =
(CheckBox) findViewById(R.id.syncProviderOnTickle);
mSyncProviderOnTickleCheckBox.setOnClickListener(
mToggleSyncOnTickle);
updateCachedSettingsAndProviderUi();
updateStatusUi();
}
@Override
protected void onResume() {
super.onResume();
mActiveSyncQueryMap.setKeepUpdated(true);
}
@Override
protected void onPause() {
super.onPause();
mActiveSyncQueryMap.setKeepUpdated(false);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mActiveSyncQueryMap != null) {
mActiveSyncQueryMap.close();
mActiveSyncQueryMap = null;
}
}
private void setSyncButton(int state) {
if (state == CANCEL_BUTTON) {
mSyncButton.setOnClickListener(mCancelSync);
mSyncButton.setText("Cancel");
} else {
mSyncButton.setOnClickListener(mStartSync);
mSyncButton.setText("Sync");
}
}
private void doSync() {
mStatusView.setText("Syncing");
setSyncButton(CANCEL_BUTTON);
Uri filter = null;
String providerName = getSelectedProviderName();
if (providerName != null) {
filter = Uri.parse("content://" + providerName);
}
Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
getContentResolver().startSync(filter, extras);
}
/**
* Returns the name of the selected provider, or null if "all" is selected.
*
* @return the name of the selected provider, or null if "all" is selected
*/
private String getSelectedProviderName() {
int selectedIndex = mContentNameSpinner.getSelectedItemPosition();
if (selectedIndex != 0) {
return (String) mProviderNames.get(selectedIndex);
} else {
return null;
}
}
private Observer mSyncObserver = new Observer() {
public void update(Observable o, Object arg) {
updateStatusUi();
}
};
private int mProgressCount = 0;
private String nextProgressText() {
int progressCount = mProgressCount;
mProgressCount++;
switch (progressCount) {
case 0: return "|";
case 1: return "/";
case 2: return "-";
default:
mProgressCount = 0;
return "\\";
}
}
private void updateStatusUi() {
ContentValues syncInfo = mActiveSyncQueryMap.getActiveSyncInfo();
boolean syncing = syncInfo != null;
if (!syncing) {
ContentValues values = queryPreviousSyncInfo();
if (values == null) {
mAccountTextView.setVisibility(View.INVISIBLE);
mStatusView.setText("The sync history is empty");
mMoreStatusView.setText("");
} else {
mAccountTextView.setVisibility(View.VISIBLE);
String account = values.getAsString(android.provider.Sync.History.ACCOUNT);
String authority = values.getAsString(android.provider.Sync.History.AUTHORITY);
long elapsedTime = values.getAsLong(android.provider.Sync.History.ELAPSED_TIME);
String result = android.provider.Sync.History.mesgToString(
values.getAsString(android.provider.Sync.History.MESG));
mAccountTextView.setText("Account: " + account);
mStatusView.setText("spent " + (elapsedTime / 1000) + " second(s) on "
+ authority);
mMoreStatusView.setText("result: " + result);
}
} else {
String account = syncInfo.getAsString(android.provider.Sync.Active.ACCOUNT);
String authority = syncInfo.getAsString(android.provider.Sync.Active.AUTHORITY);
mAccountTextView.setVisibility(View.VISIBLE);
mAccountTextView.setText("Account: " + account);
mStatusView.setText("Syncing " + authority);
mMoreStatusView.setText(nextProgressText());
}
if (syncing) {
setSyncButton(CANCEL_BUTTON);
} else {
setSyncButton(SYNC_BUTTON);
}
}
private synchronized void updateProviderUi() {
String providerName = getSelectedProviderName();
if (providerName != null) {
boolean syncOnTickle = mProvidersToTickle.get(providerName);
String text = "Sync " + providerName +
" when changes happen on the server";
mSyncProviderOnTickleCheckBox.setChecked(syncOnTickle);
mSyncProviderOnTickleCheckBox.setText(text);
mSyncProviderOnTickleCheckBox.setVisibility(View.VISIBLE);
} else {
mSyncProviderOnTickleCheckBox.setVisibility(View.INVISIBLE);
}
}
private synchronized void updateCachedSettingsAndProviderUi() {
if (mProvidersToTickle == null) {
mProvidersToTickle = new HashMap<String, Boolean>();
Adapter adapter = mContentNameSpinner.getAdapter();
int numProviders = adapter.getCount();
for (int i = 0; i < numProviders; i++) {
mProvidersToTickle.put((String) adapter.getItem(i), false);
}
}
for (String provider : mProvidersToTickle.keySet()) {
mProvidersToTickle.put(provider, mSyncSettings.getSyncProviderAutomatically(provider));
}
mListenForTicklesCheckBox.setChecked(mSyncSettings.getListenForNetworkTickles());
updateProviderUi();
}
private ContentValues queryPreviousSyncInfo() {
Cursor c = getContentResolver().query(android.provider.Sync.History.CONTENT_URI, null,
"event=" + android.provider.Sync.History.EVENT_STOP, null,
android.provider.Sync.History.EVENT_TIME + " desc");
try {
if (c.moveToNext()) {
ContentValues values = new ContentValues();
DatabaseUtils.cursorRowToContentValues(c, values);
return values;
} else {
return null;
}
} finally {
c.close();
}
}
}