Merge branch 'develop' into automationTest

This commit is contained in:
purigarcia 2015-05-06 19:05:03 +02:00
commit 6a9dfdb330
14 changed files with 1114 additions and 920 deletions

View file

@ -151,7 +151,7 @@
<service android:name=".files.services.FileUploader" /> <service android:name=".files.services.FileUploader" />
<service android:name=".media.MediaService" /> <service android:name=".media.MediaService" />
<activity android:name=".ui.activity.PinCodeActivity" /> <activity android:name=".ui.activity.PassCodeActivity" />
<activity android:name=".ui.activity.ConflictsResolveActivity"/> <activity android:name=".ui.activity.ConflictsResolveActivity"/>
<activity android:name=".ui.activity.GenericExplanationActivity"/> <activity android:name=".ui.activity.GenericExplanationActivity"/>
<activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/> <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>

View file

@ -1,78 +1,88 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
ownCloud Android client application ownCloud Android client application
Copyright (C) 2012 Bartek Przybylski Copyright (C) 2012 Bartek Przybylski
Copyright (C) 2015 ownCloud Inc. Copyright (C) 2015 ownCloud Inc.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2, it under the terms of the GNU General Public License version 2,
as published by the Free Software Foundation. as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android" xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:orientation="vertical" android:orientation="vertical"
android:padding="20dp" > android:padding="20dp" >
<TextView <TextView
android:id="@+id/pinHdr" android:id="@+id/header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/pincode_enter_pin_code" android:text="@string/pass_code_enter_pass_code"
android:textColor="@android:color/black" android:textColor="@android:color/black"
android:gravity="center_horizontal" android:gravity="center_horizontal"
/> />
<TextView <TextView
android:id="@+id/pinHdrExpl" android:id="@+id/explanation"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/pincode_configure_your_pin_explanation" android:text="@string/pass_code_configure_your_pass_code_explanation"
android:textAppearance="@android:style/TextAppearance.Small" android:textAppearance="@android:style/TextAppearance.Small"
android:gravity="center_horizontal" android:gravity="center_horizontal"
/> />
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" > android:gravity="center_horizontal" >
<EditText <EditText
android:id="@+id/txt1" android:id="@+id/txt0"
android:focusable="true" android:focusable="true"
style="@style/PassCodeStyle" style="@style/PassCodeStyle"
android:cursorVisible="true" android:cursorVisible="true"
><requestFocus/></EditText> android:imeOptions="flagNoExtractUi"
><requestFocus/></EditText>
<EditText
android:id="@+id/txt2" <EditText
style="@style/PassCodeStyle" /> android:id="@+id/txt1"
style="@style/PassCodeStyle"
<EditText android:cursorVisible="true"
android:id="@+id/txt3" android:imeOptions="flagNoExtractUi"
style="@style/PassCodeStyle" /> />
<EditText <EditText
android:id="@+id/txt4" android:id="@+id/txt2"
style="@style/PassCodeStyle" /> style="@style/PassCodeStyle"
</LinearLayout> android:cursorVisible="true"
android:imeOptions="flagNoExtractUi"
<Button />
android:id="@+id/cancel"
android:layout_width="wrap_content" <EditText
android:layout_height="wrap_content" android:id="@+id/txt3"
android:text="@string/common_cancel" /> style="@style/PassCodeStyle"
android:cursorVisible="true"
</LinearLayout> android:imeOptions="flagNoExtractUi"
/>
</LinearLayout>
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/common_cancel" />
</LinearLayout>

View file

@ -24,8 +24,7 @@
<string name="prefs_category_more">More</string> <string name="prefs_category_more">More</string>
<string name="prefs_accounts">Accounts</string> <string name="prefs_accounts">Accounts</string>
<string name="prefs_manage_accounts">Manage Accounts</string> <string name="prefs_manage_accounts">Manage Accounts</string>
<string name="prefs_pincode">App PIN</string> <string name="prefs_passcode">Pass code lock</string>
<string name="prefs_pincode_summary">Protect your client</string>
<string name="prefs_instant_upload">Instant picture uploads</string> <string name="prefs_instant_upload">Instant picture uploads</string>
<string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string> <string name="prefs_instant_upload_summary">Instantly upload pictures taken by camera</string>
<string name="prefs_instant_video_upload">Instant video uploads</string> <string name="prefs_instant_video_upload">Instant video uploads</string>
@ -132,16 +131,16 @@
<string name="foreign_files_local_text">"Local: %1$s"</string> <string name="foreign_files_local_text">"Local: %1$s"</string>
<string name="foreign_files_remote_text">"Remote: %1$s"</string> <string name="foreign_files_remote_text">"Remote: %1$s"</string>
<string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would you like to move them instead? </string> <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would you like to move them instead? </string>
<string name="pincode_enter_pin_code">Please, insert your App PIN</string> <string name="pass_code_enter_pass_code">Please, insert your pass code</string>
<string name="pincode_configure_your_pin">Enter your App PIN</string> <string name="pass_code_configure_your_pass_code">Enter your pass code</string>
<string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string> <string name="pass_code_configure_your_pass_code_explanation">The pass code will be requested every time the app is started</string>
<string name="pincode_reenter_your_pincode">Please, reenter your App PIN</string> <string name="pass_code_reenter_your_pass_code">Please, reenter your pass code</string>
<string name="pincode_remove_your_pincode">Remove your App PIN</string> <string name="pass_code_remove_your_pass_code">Remove your pass code</string>
<string name="pincode_mismatch">The App PINs are not the same</string> <string name="pass_code_mismatch">The pass codes are not the same</string>
<string name="pincode_wrong">Incorrect App PIN</string> <string name="pass_code_wrong">Incorrect pass code</string>
<string name="pincode_removed">App PIN removed</string> <string name="pass_code_removed">Pass code removed</string>
<string name="pincode_stored">App PIN stored</string> <string name="pass_code_stored">Pass code stored</string>
<string name="media_notif_ticker">"%1$s music player"</string> <string name="media_notif_ticker">"%1$s music player"</string>
<string name="media_state_playing">"%1$s (playing)"</string> <string name="media_state_playing">"%1$s (playing)"</string>
@ -220,6 +219,7 @@
<string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string> <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
<string name="filedisplay_no_file_selected">No file was selected</string> <string name="filedisplay_no_file_selected">No file was selected</string>
<string name="activity_chooser_title">Send link to &#8230;</string> <string name="activity_chooser_title">Send link to &#8230;</string>
<string name="wait_for_tmp_copy_from_private_storage">Copying file from private storage</string>
<string name="oauth_check_onoff">Login with oAuth2</string> <string name="oauth_check_onoff">Login with oAuth2</string>
<string name="oauth_login_connection">Connecting to oAuth2 server…</string> <string name="oauth_login_connection">Connecting to oAuth2 server…</string>

View file

@ -22,13 +22,7 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/prefs_category_security"> <PreferenceCategory android:title="@string/prefs_category_security">
<!-- ListPreference <android.preference.CheckBoxPreference android:title="@string/prefs_passcode" android:key="set_pincode" />
android:key="select_oc_account"
android:title="@string/prefs_select_oc_account"
android:summary="@string/prefs_summary_select_oc_account"
/ -->
<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:title="@string/prefs_pincode" android:key="set_pincode"
android:summary="@string/prefs_pincode_summary"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/prefs_category_instant_uploading" android:key="instant_uploading_category"> <PreferenceCategory android:title="@string/prefs_category_instant_uploading" android:key="instant_uploading_category">

View file

@ -20,16 +20,21 @@
*/ */
package com.owncloud.android; package com.owncloud.android;
import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import com.owncloud.android.authentication.PassCodeManager;
import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.common.utils.Log_OC;
/** /**
* Main Application of the project * Main Application of the project
* *
@ -41,7 +46,7 @@ public class MainApp extends Application {
private static final String TAG = MainApp.class.getSimpleName(); private static final String TAG = MainApp.class.getSimpleName();
private static final String AUTH_ON = "on"; private static final String AUTH_ON = "on";
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account"; private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account";
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -75,6 +80,50 @@ public class MainApp extends Application {
Log_OC.startLogging(); Log_OC.startLogging();
Log_OC.d("Debug", "start logging"); Log_OC.d("Debug", "start logging");
} }
// register global protection with pass code
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
this.registerActivityLifecycleCallbacks( new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log_OC.d(activity.getClass().getSimpleName(), "onCreate(Bundle) starting" );
PassCodeManager.getPassCodeManager().onActivityCreated(activity);
}
@Override
public void onActivityStarted(Activity activity) {
Log_OC.d(activity.getClass().getSimpleName(), "onStart() starting" );
PassCodeManager.getPassCodeManager().onActivityStarted(activity);
}
@Override
public void onActivityResumed(Activity activity) {
Log_OC.d(activity.getClass().getSimpleName(), "onResume() starting" );
}
@Override
public void onActivityPaused(Activity activity) {
Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending");
}
@Override
public void onActivityStopped(Activity activity) {
Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending" );
PassCodeManager.getPassCodeManager().onActivityStopped(activity);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log_OC.d(activity.getClass().getSimpleName(), "onSaveInstanceState(Bundle) starting" );
}
@Override
public void onActivityDestroyed(Activity activity) {
Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending" );
}
});
}
} }
public static Context getAppContext() { public static Context getAppContext() {

View file

@ -0,0 +1,115 @@
/**
* ownCloud Android client application
*
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.owncloud.android.authentication;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.view.WindowManager;
import com.owncloud.android.MainApp;
import com.owncloud.android.ui.activity.PassCodeActivity;
import java.util.HashSet;
import java.util.Set;
public class PassCodeManager {
private static final Set<Class> sExemptOfPasscodeActivites;
static {
sExemptOfPasscodeActivites = new HashSet<Class>();
sExemptOfPasscodeActivites.add(PassCodeActivity.class);
// other activities may be exempted, if needed
}
private static int PASS_CODE_TIMEOUT = 1000;
// keeping a "low" positive value is the easiest way to prevent the pass code is requested on rotations
public static PassCodeManager mPassCodeManagerInstance = null;
public static PassCodeManager getPassCodeManager() {
if (mPassCodeManagerInstance == null) {
mPassCodeManagerInstance = new PassCodeManager();
}
return mPassCodeManagerInstance;
}
private Long mTimestamp = 0l;
private int mVisibleActivitiesCounter = 0;
protected PassCodeManager() {};
public void onActivityCreated(Activity activity) {
if (passCodeIsEnabled()) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
public void onActivityStarted(Activity activity) {
if (!sExemptOfPasscodeActivites.contains(activity.getClass()) &&
passCodeShouldBeRequested()
){
Intent i = new Intent(MainApp.getAppContext(), PassCodeActivity.class);
i.setAction(PassCodeActivity.ACTION_REQUEST);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
activity.startActivity(i);
}
mVisibleActivitiesCounter++; // keep it AFTER passCodeShouldBeRequested was checked
}
public void onActivityStopped(Activity activity) {
if (mVisibleActivitiesCounter > 0) {
mVisibleActivitiesCounter--;
}
setUnlockTimestamp();
PowerManager powerMgr = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
if (passCodeIsEnabled() && powerMgr != null && !powerMgr.isScreenOn()) {
activity.moveTaskToBack(true);
}
}
private void setUnlockTimestamp() {
mTimestamp = System.currentTimeMillis();
}
private boolean passCodeShouldBeRequested(){
if ((System.currentTimeMillis() - mTimestamp) > PASS_CODE_TIMEOUT &&
mVisibleActivitiesCounter <= 0
){
return passCodeIsEnabled();
}
return false;
}
private boolean passCodeIsEnabled() {
SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext());
return (appPrefs.getBoolean("set_pincode", false));
}
}

View file

@ -197,42 +197,34 @@ public class FileActivity extends SherlockFragmentActivity
@Override @Override
protected void onStart() { protected void onStart() {
Log_OC.v(TAG, "onStart() start");
super.onStart(); super.onStart();
if (mAccountWasSet) { if (mAccountWasSet) {
onAccountSet(mAccountWasRestored); onAccountSet(mAccountWasRestored);
} }
Log_OC.v(TAG, "onStart() end");
} }
@Override @Override
protected void onResume() { protected void onResume() {
Log_OC.v(TAG, "onResume() start");
super.onResume(); super.onResume();
if (mOperationsServiceBinder != null) { if (mOperationsServiceBinder != null) {
doOnResumeAndBound(); doOnResumeAndBound();
} }
Log_OC.v(TAG, "onResume() end");
} }
@Override @Override
protected void onPause() { protected void onPause() {
Log_OC.v(TAG, "onPause() start");
if (mOperationsServiceBinder != null) { if (mOperationsServiceBinder != null) {
mOperationsServiceBinder.removeOperationListener(this); mOperationsServiceBinder.removeOperationListener(this);
} }
super.onPause(); super.onPause();
Log_OC.v(TAG, "onPause() end");
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Log_OC.v(TAG, "onDestroy() start");
if (mOperationsServiceConnection != null) { if (mOperationsServiceConnection != null) {
unbindService(mOperationsServiceConnection); unbindService(mOperationsServiceConnection);
mOperationsServiceBinder = null; mOperationsServiceBinder = null;
@ -247,7 +239,6 @@ public class FileActivity extends SherlockFragmentActivity
} }
super.onDestroy(); super.onDestroy();
Log_OC.v(TAG, "onDestroy() end");
} }

View file

@ -153,22 +153,15 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
private OCFile mWaitingToSend; private OCFile mWaitingToSend;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
Log_OC.d(TAG, "onCreate() start"); Log_OC.v(TAG, "onCreate() start");
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
// PIN CODE request ; best location is to decide, let's try this first /// grant that FileObserverService is watching favorite files
if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
requestPinCode();
} else if (getIntent().getAction() == null && savedInstanceState == null) {
requestPinCode();
}
/// grant that FileObserverService is watching favourite files
if (savedInstanceState == null) { if (savedInstanceState == null) {
Intent initObserversIntent = FileObserverService.makeInitIntent(this); Intent initObserversIntent = FileObserverService.makeInitIntent(this);
startService(initObserversIntent); startService(initObserversIntent);
@ -204,22 +197,22 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
setBackgroundText(); setBackgroundText();
Log_OC.d(TAG, "onCreate() end"); Log_OC.v(TAG, "onCreate() end");
} }
@Override @Override
protected void onStart() { protected void onStart() {
Log_OC.d(TAG, "onStart() start"); Log_OC.v(TAG, "onStart() start");
super.onStart(); super.onStart();
getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId()); getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
Log_OC.d(TAG, "onStart() end"); Log_OC.v(TAG, "onStart() end");
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Log_OC.d(TAG, "onDestroy() start"); Log_OC.v(TAG, "onDestroy() start");
super.onDestroy(); super.onDestroy();
Log_OC.d(TAG, "onDestroy() end"); Log_OC.v(TAG, "onDestroy() end");
} }
/** /**
@ -532,10 +525,6 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
sortByDate(false); sortByDate(false);
break; break;
// TODO re-enable when server-side folder size calculation is available
// case 2:
// sortBySize(false);
// break;
} }
dialog.dismiss(); dialog.dismiss();
@ -781,21 +770,21 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
// responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
Log_OC.d(TAG, "onSaveInstanceState() start"); Log_OC.v(TAG, "onSaveInstanceState() start");
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview); outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress); outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
//outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress); //outState.putBoolean(FileDisplayActivity.KEY_REFRESH_SHARES_IN_PROGRESS, mRefreshSharesInProgress);
outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend); outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND, mWaitingToSend);
Log_OC.d(TAG, "onSaveInstanceState() end"); Log_OC.v(TAG, "onSaveInstanceState() end");
} }
@Override @Override
protected void onResume() { protected void onResume() {
Log_OC.d(TAG, "onResume() start"); Log_OC.v(TAG, "onResume() start");
super.onResume(); super.onResume();
// refresh list of files // refresh list of files
@ -822,13 +811,13 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
mDownloadFinishReceiver = new DownloadFinishReceiver(); mDownloadFinishReceiver = new DownloadFinishReceiver();
registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
Log_OC.d(TAG, "onResume() end"); Log_OC.v(TAG, "onResume() end");
} }
@Override @Override
protected void onPause() { protected void onPause() {
Log_OC.d(TAG, "onPause() start"); Log_OC.v(TAG, "onPause() start");
if (mSyncBroadcastReceiver != null) { if (mSyncBroadcastReceiver != null) {
unregisterReceiver(mSyncBroadcastReceiver); unregisterReceiver(mSyncBroadcastReceiver);
//LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver); //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
@ -843,9 +832,8 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
mDownloadFinishReceiver = null; mDownloadFinishReceiver = null;
} }
super.onPause(); super.onPause();
Log_OC.d(TAG, "onPause() end"); Log_OC.v(TAG, "onPause() end");
} }
/** /**
@ -1324,23 +1312,6 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
} }
}; };
/**
* Launch an intent to request the PIN code to the user before letting him use the app
*/
private void requestPinCode() {
boolean pinStart = false;
SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
pinStart = appPrefs.getBoolean("set_pincode", false);
if (pinStart) {
Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");
startActivity(i);
}
}
@Override @Override
public void onSavedCertificate() { public void onSavedCertificate() {
startSyncFolderOperation(getCurrentDir(), false); startSyncFolderOperation(getCurrentDir(), false);

View file

@ -0,0 +1,499 @@
/**
* ownCloud Android client application
*
* @author Bartek Przybylski
* @author masensio
* @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.owncloud.android.ui.activity;
import java.util.Arrays;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.utils.DisplayUtils;
public class PassCodeActivity extends SherlockFragmentActivity {
private static final String TAG = PassCodeActivity.class.getSimpleName();
public final static String ACTION_ENABLE = PassCodeActivity.class.getCanonicalName() + ".ENABLE";
public final static String ACTION_DISABLE = PassCodeActivity.class.getCanonicalName() + ".DISABLE";
public final static String ACTION_REQUEST = PassCodeActivity.class.getCanonicalName() + ".REQUEST";
private Button mBCancel;
private TextView mPassCodeHdr;
private TextView mPassCodeHdrExplanation;
private EditText[] mPassCodeEditTexts = new EditText[4];
private String [] mPassCodeDigits = {"","","",""};
private boolean mConfirmingPassCode = false;
private boolean mBChange = true; // to control that only one blocks jump
/**
* Initializes the activity.
*
* An intent with a valid ACTION is expected; if none is found, an {@link IllegalArgumentException} will be thrown.
*
* @param savedInstanceState Previously saved state - irrelevant in this case
*/
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.passcodelock);
mBCancel = (Button) findViewById(R.id.cancel);
mPassCodeHdr = (TextView) findViewById(R.id.header);
mPassCodeHdrExplanation = (TextView) findViewById(R.id.explanation);
mPassCodeEditTexts[0] = (EditText) findViewById(R.id.txt0);
mPassCodeEditTexts[0].requestFocus();
getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mPassCodeEditTexts[1] = (EditText) findViewById(R.id.txt1);
mPassCodeEditTexts[2] = (EditText) findViewById(R.id.txt2);
mPassCodeEditTexts[3] = (EditText) findViewById(R.id.txt3);
if (ACTION_REQUEST.equals(getIntent().getAction())) {
/// this is a pass code request; the user has to input the right value
mPassCodeHdr.setText(R.string.pass_code_enter_pass_code);
mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
setCancelButtonEnabled(false); // no option to cancel
} else if (ACTION_ENABLE.equals(getIntent().getAction())) {
/// pass code preference has just been activated in Preferences; will receive and confirm pass code value
mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code);
//mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); // TODO choose a header, check iOS
mPassCodeHdrExplanation.setVisibility(View.VISIBLE);
setCancelButtonEnabled(true);
} else if (ACTION_DISABLE.equals(getIntent().getAction())) {
/// pass code preference has just been disabled in Preferences;
// will confirm user knows pass code, then remove it
mPassCodeHdr.setText(R.string.pass_code_remove_your_pass_code);
mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
setCancelButtonEnabled(true);
} else {
throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to " + TAG);
}
setTextListeners();
ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
}
/**
* Enables or disables the cancel button to allow the user interrupt the ACTION requested to the activity.
*
* @param enabled 'True' makes the cancel button available, 'false' hides it.
*/
protected void setCancelButtonEnabled(boolean enabled){
if(enabled){
mBCancel.setVisibility(View.VISIBLE);
mBCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
revertActionAndExit();
}
});
} else {
mBCancel.setVisibility(View.GONE);
mBCancel.setVisibility(View.INVISIBLE);
mBCancel.setOnClickListener(null);
}
}
/**
* Binds the appropiate listeners to the input boxes receiving each digit of the pass code.
*/
protected void setTextListeners() {
/// First input field
mPassCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false));
/*------------------------------------------------
* SECOND BOX
-------------------------------------------------*/
mPassCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false));
mPassCodeEditTexts[1].setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) { // TODO WIP: event should be used to control what's exactly happening with DEL, not any custom field...
mPassCodeEditTexts[0].setText("");
mPassCodeEditTexts[0].requestFocus();
if (!mConfirmingPassCode)
mPassCodeDigits[0] = "";
mBChange = false;
} else if (!mBChange) {
mBChange = true;
}
return false;
}
});
mPassCodeEditTexts[1].setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
/// TODO WIP: should take advantage of hasFocus to reduce processing
if (mPassCodeEditTexts[0].getText().toString().equals("")) { // TODO WIP validation could be done in a global way, with a single OnFocusChangeListener for all the input fields
mPassCodeEditTexts[0].requestFocus();
}
}
});
/*------------------------------------------------
* THIRD BOX
-------------------------------------------------*/
mPassCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false));
mPassCodeEditTexts[2].setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
mPassCodeEditTexts[1].requestFocus();
if (!mConfirmingPassCode)
mPassCodeDigits[1] = "";
mPassCodeEditTexts[1].setText("");
mBChange = false;
} else if (!mBChange) {
mBChange = true;
}
return false;
}
});
mPassCodeEditTexts[2].setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (mPassCodeEditTexts[0].getText().toString().equals("")) {
mPassCodeEditTexts[0].requestFocus();
} else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
mPassCodeEditTexts[1].requestFocus();
}
}
});
/*------------------------------------------------
* FOURTH BOX
-------------------------------------------------*/
mPassCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true));
mPassCodeEditTexts[3].setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
mPassCodeEditTexts[2].requestFocus();
if (!mConfirmingPassCode)
mPassCodeDigits[2] = "";
mPassCodeEditTexts[2].setText("");
mBChange = false;
} else if (!mBChange) {
mBChange = true;
}
return false;
}
});
mPassCodeEditTexts[3].setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (mPassCodeEditTexts[0].getText().toString().equals("")) {
mPassCodeEditTexts[0].requestFocus();
} else if (mPassCodeEditTexts[1].getText().toString().equals("")) {
mPassCodeEditTexts[1].requestFocus();
} else if (mPassCodeEditTexts[2].getText().toString().equals("")) {
mPassCodeEditTexts[2].requestFocus();
}
}
});
} // end setTextListener
/**
* Processes the pass code entered by the user just after the last digit was in.
*
* Takes into account the action requested to the activity, the currently saved pass code and the previously
* typed pass code, if any.
*/
private void processFullPassCode() {
if (ACTION_REQUEST.equals(getIntent().getAction())) {
if (checkPassCode()) {
/// pass code accepted in request, user is allowed to access the app
finish();
} else {
showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
}
} else if (ACTION_DISABLE.equals(getIntent().getAction())) {
if (checkPassCode()) {
/// pass code accepted when disabling, pass code is removed
SharedPreferences.Editor appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
appPrefs.putBoolean("set_pincode", false); // TODO remove; this should be unnecessary, was done before entering in the activity
appPrefs.commit();
Toast.makeText(PassCodeActivity.this, R.string.pass_code_removed, Toast.LENGTH_LONG).show();
finish();
} else {
showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
}
} else if (ACTION_ENABLE.equals(getIntent().getAction())) {
/// enabling pass code
if (!mConfirmingPassCode) {
requestPassCodeConfirmation();
} else if (confirmPassCode()) {
/// confirmed: user typed the same pass code twice
savePassCodeAndExit();
} else {
showErrorAndRestart(
R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE
);
}
}
}
private void showErrorAndRestart(int errorMessage, int headerMessage, int explanationVisibility) {
Arrays.fill(mPassCodeDigits, null);
CharSequence errorSeq = getString(errorMessage);
Toast.makeText(this, errorSeq, Toast.LENGTH_LONG).show();
mPassCodeHdr.setText(headerMessage); // TODO check if really needed
mPassCodeHdrExplanation.setVisibility(explanationVisibility); // TODO check if really needed
clearBoxes();
}
/**
* Ask to the user for retyping the pass code just entered before saving it as the current pass code.
*/
protected void requestPassCodeConfirmation(){
clearBoxes();
mPassCodeHdr.setText(R.string.pass_code_reenter_your_pass_code);
mPassCodeHdrExplanation.setVisibility(View.INVISIBLE);
mConfirmingPassCode = true;
}
/**
* Compares pass code entered by the user with the value currently saved in the app.
*
* @return 'True' if entered pass code equals to the saved one.
*/
protected boolean checkPassCode(){
SharedPreferences appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
String savedPassCodeDigits[] = new String[4];
savedPassCodeDigits[0] = appPrefs.getString("PrefPinCode1", null);
savedPassCodeDigits[1] = appPrefs.getString("PrefPinCode2", null);
savedPassCodeDigits[2] = appPrefs.getString("PrefPinCode3", null);
savedPassCodeDigits[3] = appPrefs.getString("PrefPinCode4", null);
boolean result = true;
for (int i = 0; i < mPassCodeDigits.length && result; i++) {
result = result && (mPassCodeDigits[i] != null) && mPassCodeDigits[i].equals(savedPassCodeDigits[i]);
}
return result;
}
/**
* Compares pass code retyped by the user in the input fields with the value entered just before.
*
* @return 'True' if retyped pass code equals to the entered before.
*/
protected boolean confirmPassCode(){
mConfirmingPassCode = false;
boolean result = true;
for (int i = 0; i < mPassCodeEditTexts.length && result; i++) {
result = result && ((mPassCodeEditTexts[i].getText().toString()).equals(mPassCodeDigits[i]));
}
return result;
}
/**
* Sets the input fields to empty strings and puts the focus on the first one.
*/
protected void clearBoxes(){
for (int i=0; i < mPassCodeEditTexts.length; i++) {
mPassCodeEditTexts[i].setText("");
}
mPassCodeEditTexts[0].requestFocus();
}
/**
* Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while preventing
* than ACTION_REQUEST may be worked around.
*
* @param keyCode Key code of the key that triggered the down event.
* @param event Event triggered.
* @return 'True' when the key event was processed by this method.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
if (ACTION_ENABLE.equals(getIntent().getAction()) || ACTION_DISABLE.equals(getIntent().getAction())) {
revertActionAndExit();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* Saves the pass code input by the user as the current pass code.
*/
protected void savePassCodeAndExit() {
SharedPreferences.Editor appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
appPrefs.putString("PrefPinCode1", mPassCodeDigits[0]);
appPrefs.putString("PrefPinCode2", mPassCodeDigits[1]);
appPrefs.putString("PrefPinCode3", mPassCodeDigits[2]);
appPrefs.putString("PrefPinCode4", mPassCodeDigits[3]);
appPrefs.putBoolean("set_pincode", true); /// TODO remove; unnecessary, Preferences did it before entering here
appPrefs.commit();
Toast.makeText(this, R.string.pass_code_stored, Toast.LENGTH_LONG).show();
finish();
}
/**
* Cancellation of ACTION_ENABLE or ACTION_DISABLE; reverts the enable or disable action done by
* {@link Preferences}, then finishes.
*/
protected void revertActionAndExit() {
SharedPreferences.Editor appPrefsE = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
SharedPreferences appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
boolean state = appPrefs.getBoolean("set_pincode", false);
appPrefsE.putBoolean("set_pincode", !state);
// TODO WIP: this is reverting the value of the preference because it was changed BEFORE entering
// TODO in this activity; was the PreferenceCheckBox in the caller who did it
appPrefsE.commit();
finish();
}
private class PassCodeDigitTextWatcher implements TextWatcher {
private int mIndex = -1;
private boolean mLastOne = false;
/**
* Constructor
*
* @param index Position in the pass code of the input field that will be bound to this watcher.
* @param lastOne 'True' means that watcher corresponds to the last position of the pass code.
*/
public PassCodeDigitTextWatcher(int index, boolean lastOne) {
mIndex = index;
mLastOne = lastOne;
if (mIndex < 0) {
throw new IllegalArgumentException(
"Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + " constructor"
);
}
}
private int next() {
return mLastOne ? 0 : mIndex + 1;
}
/**
* Performs several actions when the user types a digit in an input field:
* - saves the input digit to the state of the activity; this will allow retyping the pass code to confirm it.
* - moves the focus automatically to the next field
* - for the last field, triggers the processing of the full pass code
*
* @param s
*/
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
if (!mConfirmingPassCode) {
mPassCodeDigits[mIndex] = mPassCodeEditTexts[mIndex].getText().toString();
}
mPassCodeEditTexts[next()].requestFocus();
if (mLastOne) {
processFullPassCode();
}
} else {
Log_OC.d(TAG, "Text box " + mIndex + " was cleaned");
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// nothing to do
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// nothing to do
}
}
}

View file

@ -1,644 +0,0 @@
/**
* ownCloud Android client application
*
* Copyright (C) 2011 Bartek Przybylski
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.owncloud.android.ui.activity;
import java.util.Arrays;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.R;
import com.owncloud.android.utils.DisplayUtils;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class PinCodeActivity extends SherlockFragmentActivity {
public final static String EXTRA_ACTIVITY = "com.owncloud.android.ui.activity.PinCodeActivity.ACTIVITY";
public final static String EXTRA_NEW_STATE = "com.owncloud.android.ui.activity.PinCodeActivity.NEW_STATE";
private Button mBCancel;
private TextView mPinHdr;
private TextView mPinHdrExplanation;
private EditText mText1;
private EditText mText2;
private EditText mText3;
private EditText mText4;
private String [] mTempText ={"","","",""};
private String mActivity;
private boolean mConfirmingPinCode = false;
private boolean mPinCodeChecked = false;
private boolean mNewPasswordEntered = false;
private boolean mBChange = true; // to control that only one blocks jump
//private int mTCounter ; // Count the number of attempts an user could introduce the PIN code
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pincodelock);
Intent intent = getIntent();
mActivity = intent.getStringExtra(EXTRA_ACTIVITY);
mBCancel = (Button) findViewById(R.id.cancel);
mPinHdr = (TextView) findViewById(R.id.pinHdr);
mPinHdrExplanation = (TextView) findViewById(R.id.pinHdrExpl);
mText1 = (EditText) findViewById(R.id.txt1);
mText1.requestFocus();
getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mText2 = (EditText) findViewById(R.id.txt2);
mText3 = (EditText) findViewById(R.id.txt3);
mText4 = (EditText) findViewById(R.id.txt4);
SharedPreferences appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
// Not PIN Code defined yet.
// In a previous version settings is allow from start
if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){
setChangePincodeView(true);
mPinCodeChecked = true;
mNewPasswordEntered = true;
}else{
if (appPrefs.getBoolean("set_pincode", false)){
// pincode activated
if (mActivity.equals("preferences")){
// PIN has been activated yet
mPinHdr.setText(R.string.pincode_configure_your_pin);
mPinHdrExplanation.setVisibility(View.VISIBLE);
mPinCodeChecked = true ; // No need to check it
setChangePincodeView(true);
}else{
// PIN active
mBCancel.setVisibility(View.INVISIBLE);
mBCancel.setVisibility(View.GONE);
mPinHdr.setText(R.string.pincode_enter_pin_code);
mPinHdrExplanation.setVisibility(View.INVISIBLE);
setChangePincodeView(false);
}
}else {
// pincode removal
mPinHdr.setText(R.string.pincode_remove_your_pincode);
mPinHdrExplanation.setVisibility(View.INVISIBLE);
mPinCodeChecked = false;
setChangePincodeView(true);
}
}
setTextListeners();
ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId());
}
protected void setInitVars(){
mConfirmingPinCode = false;
mPinCodeChecked = false;
mNewPasswordEntered = false;
}
protected void setInitView(){
mBCancel.setVisibility(View.INVISIBLE);
mBCancel.setVisibility(View.GONE);
mPinHdr.setText(R.string.pincode_enter_pin_code);
mPinHdrExplanation.setVisibility(View.INVISIBLE);
}
protected void setChangePincodeView(boolean state){
if(state){
mBCancel.setVisibility(View.VISIBLE);
mBCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor appPrefsE = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
SharedPreferences appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
boolean state = appPrefs.getBoolean("set_pincode", false);
appPrefsE.putBoolean("set_pincode",!state);
appPrefsE.commit();
setInitVars();
finish();
}
});
}
}
/*
*
*/
protected void setTextListeners(){
/*------------------------------------------------
* FIRST BOX
-------------------------------------------------*/
mText1.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
if (!mConfirmingPinCode){
mTempText[0] = mText1.getText().toString();
}
mText2.requestFocus();
}
}
});
/*------------------------------------------------
* SECOND BOX
-------------------------------------------------*/
mText2.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
if (!mConfirmingPinCode){
mTempText[1] = mText2.getText().toString();
}
mText3.requestFocus();
}
}
});
mText2.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
mText1.setText("");
mText1.requestFocus();
if (!mConfirmingPinCode)
mTempText[0] = "";
mBChange= false;
}else if(!mBChange){
mBChange=true;
}
return false;
}
});
mText2.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
mText2.setCursorVisible(true);
if (mText1.getText().toString().equals("")){
mText2.setSelected(false);
mText2.setCursorVisible(false);
mText1.requestFocus();
mText1.setSelected(true);
mText1.setSelection(0);
}
}
});
/*------------------------------------------------
* THIRD BOX
-------------------------------------------------*/
mText3.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
if (!mConfirmingPinCode){
mTempText[2] = mText3.getText().toString();
}
mText4.requestFocus();
}
}
});
mText3.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
mText2.requestFocus();
if (!mConfirmingPinCode)
mTempText[1] = "";
mText2.setText("");
mBChange= false;
}else if(!mBChange){
mBChange=true;
}
return false;
}
});
mText3.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
mText3.setCursorVisible(true);
if (mText1.getText().toString().equals("")){
mText3.setSelected(false);
mText3.setCursorVisible(false);
mText1.requestFocus();
mText1.setSelected(true);
mText1.setSelection(0);
}else if (mText2.getText().toString().equals("")){
mText3.setSelected(false);
mText3.setCursorVisible(false);
mText2.requestFocus();
mText2.setSelected(true);
mText2.setSelection(0);
}
}
});
/*------------------------------------------------
* FOURTH BOX
-------------------------------------------------*/
mText4.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
if (!mConfirmingPinCode){
mTempText[3] = mText4.getText().toString();
}
mText1.requestFocus();
if (!mPinCodeChecked){
mPinCodeChecked = checkPincode();
}
if (mPinCodeChecked &&
( mActivity.equals("FileDisplayActivity") || mActivity.equals("PreviewImageActivity") ) ){
finish();
} else if (mPinCodeChecked){
Intent intent = getIntent();
String newState = intent.getStringExtra(EXTRA_NEW_STATE);
if (newState.equals("false")){
SharedPreferences.Editor appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
appPrefs.putBoolean("set_pincode",false);
appPrefs.commit();
setInitVars();
pinCodeEnd(false);
}else{
if (!mConfirmingPinCode){
pinCodeChangeRequest();
} else {
confirmPincode();
}
}
}
}
}
});
mText4.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) {
mText3.requestFocus();
if (!mConfirmingPinCode)
mTempText[2]="";
mText3.setText("");
mBChange= false;
}else if(!mBChange){
mBChange=true;
}
return false;
}
});
mText4.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
mText4.setCursorVisible(true);
if (mText1.getText().toString().equals("")){
mText4.setSelected(false);
mText4.setCursorVisible(false);
mText1.requestFocus();
mText1.setSelected(true);
mText1.setSelection(0);
}else if (mText2.getText().toString().equals("")){
mText4.setSelected(false);
mText4.setCursorVisible(false);
mText2.requestFocus();
mText2.setSelected(true);
mText2.setSelection(0);
}else if (mText3.getText().toString().equals("")){
mText4.setSelected(false);
mText4.setCursorVisible(false);
mText3.requestFocus();
mText3.setSelected(true);
mText3.setSelection(0);
}
}
});
} // end setTextListener
protected void pinCodeChangeRequest(){
clearBoxes();
mPinHdr.setText(R.string.pincode_reenter_your_pincode);
mPinHdrExplanation.setVisibility(View.INVISIBLE);
mConfirmingPinCode =true;
}
protected boolean checkPincode(){
SharedPreferences appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
String pText1 = appPrefs.getString("PrefPinCode1", null);
String pText2 = appPrefs.getString("PrefPinCode2", null);
String pText3 = appPrefs.getString("PrefPinCode3", null);
String pText4 = appPrefs.getString("PrefPinCode4", null);
if ( mTempText[0].equals(pText1) &&
mTempText[1].equals(pText2) &&
mTempText[2].equals(pText3) &&
mTempText[3].equals(pText4) ) {
return true;
}else {
Arrays.fill(mTempText, null);
AlertDialog aDialog = new AlertDialog.Builder(this).create();
CharSequence errorSeq = getString(R.string.common_error);
aDialog.setTitle(errorSeq);
CharSequence cseq = getString(R.string.pincode_wrong);
aDialog.setMessage(cseq);
CharSequence okSeq = getString(R.string.common_ok);
aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
return;
}
});
aDialog.show();
clearBoxes();
mPinHdr.setText(R.string.pincode_enter_pin_code);
mPinHdrExplanation.setVisibility(View.INVISIBLE);
mNewPasswordEntered = true;
mConfirmingPinCode = false;
}
return false;
}
protected void confirmPincode(){
mConfirmingPinCode = false;
String rText1 = mText1.getText().toString();
String rText2 = mText2.getText().toString();
String rText3 = mText3.getText().toString();
String rText4 = mText4.getText().toString();
if ( mTempText[0].equals(rText1) &&
mTempText[1].equals(rText2) &&
mTempText[2].equals(rText3) &&
mTempText[3].equals(rText4) ) {
savePincodeAndExit();
} else {
Arrays.fill(mTempText, null);
AlertDialog aDialog = new AlertDialog.Builder(this).create();
CharSequence errorSeq = getString(R.string.common_error);
aDialog.setTitle(errorSeq);
CharSequence cseq = getString(R.string.pincode_mismatch);
aDialog.setMessage(cseq);
CharSequence okSeq = getString(R.string.common_ok);
aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
return;
}
});
aDialog.show();
mPinHdr.setText(R.string.pincode_configure_your_pin);
mPinHdrExplanation.setVisibility(View.VISIBLE);
clearBoxes();
}
}
protected void pinCodeEnd(boolean state){
AlertDialog aDialog = new AlertDialog.Builder(this).create();
if (state){
CharSequence saveSeq = getString(R.string.common_save_exit);
aDialog.setTitle(saveSeq);
CharSequence cseq = getString(R.string.pincode_stored);
aDialog.setMessage(cseq);
}else{
CharSequence saveSeq = getString(R.string.common_save_exit);
aDialog.setTitle(saveSeq);
CharSequence cseq = getString(R.string.pincode_removed);
aDialog.setMessage(cseq);
}
CharSequence okSeq = getString(R.string.common_ok);
aDialog.setButton(okSeq, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
return;
}
});
aDialog.show();
}
protected void savePincodeAndExit(){
SharedPreferences.Editor appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
appPrefs.putString("PrefPinCode1", mTempText[0]);
appPrefs.putString("PrefPinCode2",mTempText[1]);
appPrefs.putString("PrefPinCode3", mTempText[2]);
appPrefs.putString("PrefPinCode4", mTempText[3]);
appPrefs.putBoolean("set_pincode",true);
appPrefs.commit();
pinCodeEnd(true);
}
protected void clearBoxes(){
mText1.setText("");
mText2.setText("");
mText3.setText("");
mText4.setText("");
mText1.requestFocus();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){
if (mActivity.equals("preferences")){
SharedPreferences.Editor appPrefsE = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
SharedPreferences appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
boolean state = appPrefs.getBoolean("set_pincode", false);
appPrefsE.putBoolean("set_pincode",!state);
appPrefsE.commit();
setInitVars();
finish();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
}

View file

@ -69,8 +69,6 @@ import com.owncloud.android.services.OperationsService;
import com.owncloud.android.ui.RadioButtonPreference; import com.owncloud.android.ui.RadioButtonPreference;
import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.DisplayUtils;
import java.io.File;
/** /**
* An Activity that allows the user to change the application's settings. * An Activity that allows the user to change the application's settings.
@ -168,9 +166,11 @@ public class Preferences extends SherlockPreferenceActivity
pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override @Override
public boolean onPreferenceChange(Preference preference, Object newValue) { public boolean onPreferenceChange(Preference preference, Object newValue) {
Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); Intent i = new Intent(getApplicationContext(), PassCodeActivity.class);
i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences"); Boolean enable = (Boolean) newValue;
i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString()); i.setAction(
enable.booleanValue() ? PassCodeActivity.ACTION_ENABLE : PassCodeActivity.ACTION_DISABLE
);
startActivity(i); startActivity(i);
return true; return true;
@ -395,11 +395,6 @@ public class Preferences extends SherlockPreferenceActivity
} }
} }
@Override
protected void onPause() {
super.onPause();
}
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

View file

@ -2,6 +2,7 @@
* ownCloud Android client application * ownCloud Android client application
* *
* @author Bartek Przybylski * @author Bartek Przybylski
* @author masensio
* Copyright (C) 2012 Bartek Przybylski * Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2015 ownCloud Inc. * Copyright (C) 2015 ownCloud Inc.
* *
@ -29,6 +30,7 @@ import java.util.List;
import java.util.Stack; import java.util.Stack;
import java.util.Vector; import java.util.Vector;
import android.accounts.Account; import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.AlertDialog; import android.app.AlertDialog;
@ -47,9 +49,13 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio; import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Images; import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video; import android.provider.MediaStore.Video;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
@ -71,6 +77,8 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.operations.CreateFolderOperation; import com.owncloud.android.operations.CreateFolderOperation;
import com.owncloud.android.ui.dialog.CreateFolderDialogFragment; import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
import com.owncloud.android.ui.dialog.LoadingDialog;
import com.owncloud.android.utils.CopyTmpFileAsyncTask;
import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.ErrorMessageAdapter;
@ -79,7 +87,8 @@ import com.owncloud.android.utils.ErrorMessageAdapter;
* This can be used to upload things to an ownCloud instance. * This can be used to upload things to an ownCloud instance.
*/ */
public class Uploader extends FileActivity public class Uploader extends FileActivity
implements OnItemClickListener, android.view.View.OnClickListener { implements OnItemClickListener, android.view.View.OnClickListener,
CopyTmpFileAsyncTask.OnCopyTmpFileTaskListener {
private static final String TAG = Uploader.class.getSimpleName(); private static final String TAG = Uploader.class.getSimpleName();
@ -90,6 +99,10 @@ public class Uploader extends FileActivity
private String mUploadPath; private String mUploadPath;
private OCFile mFile; private OCFile mFile;
private boolean mAccountSelected; private boolean mAccountSelected;
private boolean mAccountSelectionShowing;
private ArrayList<String> mRemoteCacheData;
private int mNumCacheFile;
private final static int DIALOG_NO_ACCOUNT = 0; private final static int DIALOG_NO_ACCOUNT = 0;
private final static int DIALOG_WAITING = 1; private final static int DIALOG_WAITING = 1;
@ -101,6 +114,11 @@ public class Uploader extends FileActivity
private final static String KEY_PARENTS = "PARENTS"; private final static String KEY_PARENTS = "PARENTS";
private final static String KEY_FILE = "FILE"; private final static String KEY_FILE = "FILE";
private final static String KEY_ACCOUNT_SELECTED = "ACCOUNT_SELECTED"; private final static String KEY_ACCOUNT_SELECTED = "ACCOUNT_SELECTED";
private final static String KEY_ACCOUNT_SELECTION_SHOWING = "ACCOUNT_SELECTION_SHOWING";
private final static String KEY_NUM_CACHE_FILE = "NUM_CACHE_FILE";
private final static String KEY_REMOTE_CACHE_DATA = "REMOTE_CACHE_DATA";
private static final String DIALOG_WAIT_COPY_FILE = "DIALOG_WAIT_COPY_FILE";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -109,13 +127,27 @@ public class Uploader extends FileActivity
if (savedInstanceState == null) { if (savedInstanceState == null) {
mParents = new Stack<String>(); mParents = new Stack<String>();
mAccountSelected = false; mAccountSelected = false;
mAccountSelectionShowing = false;
mNumCacheFile = 0;
// ArrayList for files with path in private storage
mRemoteCacheData = new ArrayList<String>();
} else { } else {
mParents = (Stack<String>) savedInstanceState.getSerializable(KEY_PARENTS); mParents = (Stack<String>) savedInstanceState.getSerializable(KEY_PARENTS);
mFile = savedInstanceState.getParcelable(KEY_FILE); mFile = savedInstanceState.getParcelable(KEY_FILE);
mAccountSelected = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTED); mAccountSelected = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTED);
mAccountSelectionShowing = savedInstanceState.getBoolean(KEY_ACCOUNT_SELECTION_SHOWING);
mNumCacheFile = savedInstanceState.getInt(KEY_NUM_CACHE_FILE);
mRemoteCacheData = savedInstanceState.getStringArrayList(KEY_REMOTE_CACHE_DATA);
} }
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (mAccountSelected) {
setAccount((Account) savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT));
}
ActionBar actionBar = getSupportActionBar(); ActionBar actionBar = getSupportActionBar();
actionBar.setIcon(DisplayUtils.getSeasonalIconId()); actionBar.setIcon(DisplayUtils.getSeasonalIconId());
@ -129,9 +161,10 @@ public class Uploader extends FileActivity
if (accounts.length == 0) { if (accounts.length == 0) {
Log_OC.i(TAG, "No ownCloud account is available"); Log_OC.i(TAG, "No ownCloud account is available");
showDialog(DIALOG_NO_ACCOUNT); showDialog(DIALOG_NO_ACCOUNT);
} else if (accounts.length > 1 && !mAccountSelected) { } else if (accounts.length > 1 && !mAccountSelected && !mAccountSelectionShowing) {
Log_OC.i(TAG, "More than one ownCloud is available"); Log_OC.i(TAG, "More than one ownCloud is available");
showDialog(DIALOG_MULTIPLE_ACCOUNT); showDialog(DIALOG_MULTIPLE_ACCOUNT);
mAccountSelectionShowing = true;
} else { } else {
if (!savedAccount) { if (!savedAccount) {
setAccount(accounts[0]); setAccount(accounts[0]);
@ -160,6 +193,10 @@ public class Uploader extends FileActivity
//outState.putParcelable(KEY_ACCOUNT, mAccount); //outState.putParcelable(KEY_ACCOUNT, mAccount);
outState.putParcelable(KEY_FILE, mFile); outState.putParcelable(KEY_FILE, mFile);
outState.putBoolean(KEY_ACCOUNT_SELECTED, mAccountSelected); outState.putBoolean(KEY_ACCOUNT_SELECTED, mAccountSelected);
outState.putBoolean(KEY_ACCOUNT_SELECTION_SHOWING, mAccountSelectionShowing);
outState.putInt(KEY_NUM_CACHE_FILE, mNumCacheFile);
outState.putStringArrayList(KEY_REMOTE_CACHE_DATA, mRemoteCacheData);
outState.putParcelable(FileActivity.EXTRA_ACCOUNT, getAccount());
Log_OC.d(TAG, "onSaveInstanceState() end"); Log_OC.d(TAG, "onSaveInstanceState() end");
} }
@ -225,12 +262,14 @@ public class Uploader extends FileActivity
onAccountSet(mAccountWasRestored); onAccountSet(mAccountWasRestored);
dialog.dismiss(); dialog.dismiss();
mAccountSelected = true; mAccountSelected = true;
mAccountSelectionShowing = false;
} }
}); });
builder.setCancelable(true); builder.setCancelable(true);
builder.setOnCancelListener(new OnCancelListener() { builder.setOnCancelListener(new OnCancelListener() {
@Override @Override
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
mAccountSelectionShowing = false;
dialog.cancel(); dialog.cancel();
finish(); finish();
} }
@ -366,7 +405,7 @@ public class Uploader extends FileActivity
actionBar.setHomeButtonEnabled(notRoot); actionBar.setHomeButtonEnabled(notRoot);
String full_path = generatePath(mParents); String full_path = generatePath(mParents);
Log_OC.d(TAG, "Populating view with content of : " + full_path); Log_OC.d(TAG, "Populating view with content of : " + full_path);
mFile = getStorageManager().getFileByPath(full_path); mFile = getStorageManager().getFileByPath(full_path);
@ -421,6 +460,7 @@ public class Uploader extends FileActivity
public void uploadFiles() { public void uploadFiles() {
try { try {
// ArrayList for files with path in external storage
ArrayList<String> local = new ArrayList<String>(); ArrayList<String> local = new ArrayList<String>();
ArrayList<String> remote = new ArrayList<String>(); ArrayList<String> remote = new ArrayList<String>();
@ -428,101 +468,106 @@ public class Uploader extends FileActivity
for (Parcelable mStream : mStreamsToUpload) { for (Parcelable mStream : mStreamsToUpload) {
Uri uri = (Uri) mStream; Uri uri = (Uri) mStream;
if (uri !=null) { String data = null;
String filePath = "";
if (uri != null) {
if (uri.getScheme().equals("content")) { if (uri.getScheme().equals("content")) {
String mimeType = getContentResolver().getType(uri);
String mimeType = getContentResolver().getType(uri);
if (mimeType.contains("image")) {
if (mimeType.contains("image")) { String[] CONTENT_PROJECTION = { Images.Media.DATA,
String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE,
Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE };
Images.Media.SIZE}; Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
null, null); c.moveToFirst();
c.moveToFirst(); int index = c.getColumnIndex(Images.Media.DATA);
int index = c.getColumnIndex(Images.Media.DATA); data = c.getString(index);
String data = c.getString(index); filePath = mUploadPath +
local.add(data); c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
remote.add(mUploadPath +
c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME))); } else if (mimeType.contains("video")) {
String[] CONTENT_PROJECTION = { Video.Media.DATA,
}
else if (mimeType.contains("video")) {
String[] CONTENT_PROJECTION = { Video.Media.DATA,
Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE,
Video.Media.SIZE, Video.Media.DATE_MODIFIED }; Video.Media.SIZE, Video.Media.DATE_MODIFIED };
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
null, null); null, null);
c.moveToFirst(); c.moveToFirst();
int index = c.getColumnIndex(Video.Media.DATA); int index = c.getColumnIndex(Video.Media.DATA);
String data = c.getString(index); data = c.getString(index);
local.add(data); filePath = mUploadPath +
remote.add(mUploadPath + c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME)));
} } else if (mimeType.contains("audio")) {
else if (mimeType.contains("audio")) { String[] CONTENT_PROJECTION = { Audio.Media.DATA,
String[] CONTENT_PROJECTION = { Audio.Media.DATA,
Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE, Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE,
Audio.Media.SIZE }; Audio.Media.SIZE };
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
null, null); null, null);
c.moveToFirst(); c.moveToFirst();
int index = c.getColumnIndex(Audio.Media.DATA); int index = c.getColumnIndex(Audio.Media.DATA);
String data = c.getString(index); data = c.getString(index);
local.add(data); filePath = mUploadPath +
remote.add(mUploadPath + c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME));
c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME)));
} else {
} Cursor cursor = getContentResolver().query(uri,
else { new String[]{MediaStore.MediaColumns.DISPLAY_NAME},
String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + null, null, null);
"://", ""); cursor.moveToFirst();
// cut everything whats before mnt. It occurred to me that sometimes int nameIndex = cursor.getColumnIndex(cursor.getColumnNames()[0]);
// apps send their name into the URI if (nameIndex >= 0) {
if (filePath.contains("mnt")) { filePath = mUploadPath + cursor.getString(nameIndex);
String splitedFilePath[] = filePath.split("/mnt"); }
filePath = splitedFilePath[1]; }
}
final File file = new File(filePath);
local.add(file.getAbsolutePath());
remote.add(mUploadPath + file.getName());
}
} else if (uri.getScheme().equals("file")) { } else if (uri.getScheme().equals("file")) {
String filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + filePath = Uri.decode(uri.toString()).replace(uri.getScheme() +
"://", ""); "://", "");
if (filePath.contains("mnt")) { if (filePath.contains("mnt")) {
String splitedFilePath[] = filePath.split("/mnt"); String splitedFilePath[] = filePath.split("/mnt");
filePath = splitedFilePath[1]; filePath = splitedFilePath[1];
} }
final File file = new File(filePath); final File file = new File(filePath);
local.add(file.getAbsolutePath()); data = file.getAbsolutePath();
remote.add(mUploadPath + file.getName()); filePath = mUploadPath + file.getName();
} }
else { else {
throw new SecurityException(); throw new SecurityException();
} }
if (data == null) {
mRemoteCacheData.add(filePath);
CopyTmpFileAsyncTask copyTask = new CopyTmpFileAsyncTask(this);
Object[] params = { uri, filePath, mRemoteCacheData.size()-1,
getAccount().name, getContentResolver()};
mNumCacheFile++;
showWaitingCopyDialog();
copyTask.execute(params);
} else {
remote.add(filePath);
local.add(data);
}
} }
else { else {
throw new SecurityException(); throw new SecurityException();
} }
Intent intent = new Intent(getApplicationContext(), FileUploader.class);
intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
intent.putExtra(FileUploader.KEY_REMOTE_FILE,
remote.toArray(new String[remote.size()]));
intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
startService(intent);
//Save the path to shared preferences Intent intent = new Intent(getApplicationContext(), FileUploader.class);
SharedPreferences.Editor appPrefs = PreferenceManager intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
.getDefaultSharedPreferences(getApplicationContext()).edit(); intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
appPrefs.putString("last_upload_path", mUploadPath); intent.putExtra(FileUploader.KEY_REMOTE_FILE,
appPrefs.apply(); remote.toArray(new String[remote.size()]));
intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
startService(intent);
finish(); //Save the path to shared preferences
SharedPreferences.Editor appPrefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
appPrefs.putString("last_upload_path", mUploadPath);
appPrefs.apply();
finish();
} }
} catch (SecurityException e) { } catch (SecurityException e) {
@ -588,16 +633,15 @@ public class Uploader extends FileActivity
// "/" equals root-directory // "/" equals root-directory
if(last_path.equals("/")) { if(last_path.equals("/")) {
mParents.add(""); mParents.add("");
} } else{
else{
String[] dir_names = last_path.split("/"); String[] dir_names = last_path.split("/");
for (String dir : dir_names) for (String dir : dir_names)
mParents.add(dir); mParents.add(dir);
} }
//Make sure that path still exists, if it doesn't pop the stack and try the previous path //Make sure that path still exists, if it doesn't pop the stack and try the previous path
while(!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1){ while(!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1){
mParents.pop(); mParents.pop();
} }
} }
@ -605,17 +649,67 @@ public class Uploader extends FileActivity
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true; boolean retval = true;
switch (item.getItemId()) { switch (item.getItemId()) {
case android.R.id.home: { case android.R.id.home:
if((mParents.size() > 1)) { if((mParents.size() > 1)) {
onBackPressed(); onBackPressed();
} }
break; break;
}
default: default:
retval = super.onOptionsItemSelected(item); retval = super.onOptionsItemSelected(item);
} }
return retval; return retval;
} }
/**
* Process the result of CopyTmpFileAsyncTask
* @param result
* @param index
*/
@Override
public void onTmpFileCopied(String result, int index) {
if (mNumCacheFile -- == 0) {
dismissWaitingCopyDialog();
}
if (result != null) {
Intent intent = new Intent(getApplicationContext(), FileUploader.class);
intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
intent.putExtra(FileUploader.KEY_LOCAL_FILE, result);
intent.putExtra(FileUploader.KEY_REMOTE_FILE, mRemoteCacheData.get(index));
intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
startService(intent);
} else {
String message = String.format(getString(R.string.uploader_error_forbidden_content),
getString(R.string.app_name));
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
Log_OC.d(TAG, message);
}
}
/**
* Show waiting for copy dialog
*/
public void showWaitingCopyDialog() {
// Construct dialog
LoadingDialog loading = new LoadingDialog(
getResources().getString(R.string.wait_for_tmp_copy_from_private_storage));
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
loading.show(ft, DIALOG_WAIT_COPY_FILE);
}
/**
* Dismiss waiting for copy dialog
*/
public void dismissWaitingCopyDialog(){
Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_COPY_FILE);
if (frag != null) {
LoadingDialog loading = (LoadingDialog) frag;
loading.dismiss();
}
}
} }

View file

@ -26,13 +26,11 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.view.View; import android.view.View;
@ -58,7 +56,6 @@ import com.owncloud.android.operations.RemoveFileOperation;
import com.owncloud.android.operations.UnshareLinkOperation; import com.owncloud.android.operations.UnshareLinkOperation;
import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.activity.PinCodeActivity;
import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.DisplayUtils;
@ -90,7 +87,7 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
private View mFullScreenAnchorView; private View mFullScreenAnchorView;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -102,11 +99,6 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
actionBar.setIcon(DisplayUtils.getSeasonalIconId()); actionBar.setIcon(DisplayUtils.getSeasonalIconId());
actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.hide(); actionBar.hide();
// PIN CODE request
if (getIntent().getExtras() != null && savedInstanceState == null && fromNotification()) {
requestPinCode();
}
// Make sure we're running on Honeycomb or higher to use FullScreen and // Make sure we're running on Honeycomb or higher to use FullScreen and
// Immersive Mode // Immersive Mode
@ -323,7 +315,7 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
//Log_OC.e(TAG, "ACTIVITY, ONRESUME");
mDownloadFinishReceiver = new DownloadFinishReceiver(); mDownloadFinishReceiver = new DownloadFinishReceiver();
IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage()); IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage());
@ -333,14 +325,16 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
@Override @Override
protected void onPostResume() { protected void onPostResume() {
//Log_OC.e(TAG, "ACTIVITY, ONPOSTRESUME");
super.onPostResume(); super.onPostResume();
} }
@Override @Override
public void onPause() { public void onPause() {
unregisterReceiver(mDownloadFinishReceiver); if (mDownloadFinishReceiver != null){
mDownloadFinishReceiver = null; unregisterReceiver(mDownloadFinishReceiver);
mDownloadFinishReceiver = null;
}
super.onPause(); super.onPause();
} }
@ -527,21 +521,6 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
} }
} }
} }
/**
* Launch an intent to request the PIN code to the user before letting him use the app
*/
private void requestPinCode() {
boolean pinStart = false;
SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
pinStart = appPrefs.getBoolean("set_pincode", false);
if (pinStart) {
Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "PreviewImageActivity");
startActivity(i);
}
}
@Override @Override
public void onBrowsedDownTo(OCFile folder) { public void onBrowsedDownTo(OCFile folder) {
@ -588,5 +567,4 @@ ViewPager.OnPageChangeListener, OnRemoteOperationListener {
} }
return false; return false;
} }
} }

View file

@ -0,0 +1,142 @@
/**
* ownCloud Android client application
*
* @author masensio
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.owncloud.android.utils;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.AsyncTask;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;
/**
* AsyncTask to copy a file from a uri in a temporal file
*/
public class CopyTmpFileAsyncTask extends AsyncTask<Object, Void, String> {
private final String TAG = CopyTmpFileAsyncTask.class.getSimpleName();
private final WeakReference<OnCopyTmpFileTaskListener> mListener;
private int mIndex;
public int getIndex(){
return mIndex;
}
public CopyTmpFileAsyncTask(OnCopyTmpFileTaskListener listener) {
mListener = new WeakReference<OnCopyTmpFileTaskListener>(listener);
}
/**
* Params for execute:
* - Uri: uri of file
* - String: path for saving the file into the app
* - int: index of upload
* - String: accountName
* - ContentResolver: content resolver
*/
@Override
protected String doInBackground(Object[] params) {
String result = null;
if (params != null && params.length == 5) {
Uri uri = (Uri) params[0];
String filePath = (String) params[1];
mIndex = ((Integer) params[2]).intValue();
String accountName = (String) params[3];
ContentResolver contentResolver = (ContentResolver) params[4];
String fullTempPath = FileStorageUtils.getTemporalPath(accountName) + filePath;
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = contentResolver.openInputStream(uri);
File cacheFile = new File(fullTempPath);
File tempDir = cacheFile.getParentFile();
if (!tempDir.exists()) {
tempDir.mkdirs();
}
cacheFile.createNewFile();
outputStream = new FileOutputStream(fullTempPath);
byte[] buffer = new byte[4096];
int count = 0;
while ((count = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, count);
}
outputStream.close();
inputStream.close();
result = fullTempPath;
} catch (Exception e) {
Log_OC.e(TAG, "Exception ", e);
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e1) {
Log_OC.e(TAG, "Input Stream Exception ", e1);
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e1) {
Log_OC.e(TAG, "Output Stream Exception ", e1);
}
}
if (fullTempPath != null) {
File f = new File(fullTempPath);
f.delete();
}
result = null;
}
} else {
throw new IllegalArgumentException("Error in parameters number");
}
return result;
}
@Override
protected void onPostExecute(String result) {
OnCopyTmpFileTaskListener listener = mListener.get();
if (listener!= null)
{
listener.onTmpFileCopied(result, mIndex);
}
}
/*
* Interface to retrieve data from recognition task
*/
public interface OnCopyTmpFileTaskListener{
void onTmpFileCopied(String result, int index);
}
}