/* * Copyright (c) 2014, Facebook, Inc. All rights reserved. * * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, * copy, modify, and distribute this software in source code or binary form for use * in connection with the web services and APIs provided by Facebook. * * As with any software that integrates with the Facebook platform, your use of * this software is subject to the Facebook Developer Principles and Policies * [http://developers.facebook.com/policy/]. This copyright notice shall be * included in all copies or substantial portions of the software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.parse.ui; import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.Window; import com.parse.Parse; import com.parse.ParseFacebookUtils; /** * Encapsulates the Parse login flow. The user can log in by username/password, * Facebook, and Twitter. If the user is new, they can also sign up. Under * normal operation, the user can only exit this activity by either successfully * logging in, or backing out of the login/signup flow. * <p/> * If your app allows Facebook/Twitter login, you must initialize * ParseFacebookUtils/ParseTwitterUtils prior to starting this activity. * <p/> * The caller activity should expect to receive one of the following resultCode * values: * <p/> * Activity.RESULT_OK: The user successfully completed login or sign-up, and we * were able to retrieve a valid ParseUser object. ParseUser.getCurrentUser() * should be populated. * <p/> * Activity.RESULT_CANCELLED: The user exited the login flow without logging in * or signing up (by clicking the back button). ParseUser.getCurrentUser() * should be null. * <p/> * You can customize this activity by: * <ul> * <li>Adding activity meta-data in your app's Manifest.xml. Please see * {@link ParseLoginConfig} for available settings.</li> * <li>Overriding any resource (layouts, strings, colors, etc) by specifying * them in your app's /res directory and using the same resource names. Your * app's resource values will override the values from this library project.</li> * <li>Using {@link ParseLoginBuilder} to construct an intent that can be used * to start this activity with your customizations.</li> * </ul> */ public class ParseLoginActivity extends FragmentActivity implements ParseLoginFragment.ParseLoginFragmentListener, ParseLoginHelpFragment.ParseOnLoginHelpSuccessListener, ParseOnLoginSuccessListener, ParseOnLoadingListener { public static final String LOG_TAG = "ParseLoginActivity"; // All login UI fragment transactions will happen within this parent layout element. // Change this if you are modifying this code to be hosted in your own activity. private final int fragmentContainer = android.R.id.content; private ProgressDialog progressDialog; private Bundle configOptions; // Although Activity.isDestroyed() is in API 17, we implement it anyways for older versions. private boolean destroyed = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); // Combine options from incoming intent and the activity metadata configOptions = getMergedOptions(); // Show the login form if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction().add(fragmentContainer, ParseLoginFragment.newInstance(configOptions)).commit(); } } @Override protected void onDestroy() { super.onDestroy(); if (progressDialog != null) { progressDialog.dismiss(); } destroyed = true; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Required for making Facebook login work ParseFacebookUtils.finishAuthentication(requestCode, resultCode, data); } /** * Called when the user clicked the sign up button on the login form. */ @Override public void onSignUpClicked(String username, String password) { // Show the signup form, but keep the transaction on the back stack // so that if the user clicks the back button, they are brought back // to the login form. FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(fragmentContainer, ParseSignupFragment.newInstance(configOptions, username, password)); transaction.addToBackStack(null); transaction.commit(); } /** * Called when the user clicked the log in button on the login form. */ @Override public void onLoginHelpClicked() { // Show the login help form for resetting the user's password. // Keep the transaction on the back stack so that if the user clicks // the back button, they are brought back to the login form. FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(fragmentContainer, ParseLoginHelpFragment.newInstance(configOptions)); transaction.addToBackStack(null); transaction.commit(); } /** * Called when the user successfully completes the login help flow. */ @Override public void onLoginHelpSuccess() { // Display the login form, which is the previous item onto the stack getSupportFragmentManager().popBackStackImmediate(); } /** * Called when the user successfully logs in or signs up. */ @Override public void onLoginSuccess() { // This default implementation returns to the parent activity with // RESULT_OK. // You can change this implementation if you want a different behavior. setResult(RESULT_OK); finish(); } /** * Called when we are in progress retrieving some data. * * @param showSpinner * Whether to show the loading dialog. */ @Override public void onLoadingStart(boolean showSpinner) { if (showSpinner) { progressDialog = ProgressDialog.show(this, null, getString(R.string.com_parse_ui_progress_dialog_text), true, false); } } /** * Called when we are finished retrieving some data. */ @Override public void onLoadingFinish() { if (progressDialog != null) { progressDialog.dismiss(); } } /** * @see android.app.Activity#isDestroyed() */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @Override public boolean isDestroyed() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { return super.isDestroyed(); } return destroyed; } private Bundle getMergedOptions() { // Read activity metadata from AndroidManifest.xml ActivityInfo activityInfo = null; try { activityInfo = getPackageManager().getActivityInfo( this.getComponentName(), PackageManager.GET_META_DATA); } catch (NameNotFoundException e) { if (Parse.getLogLevel() <= Parse.LOG_LEVEL_ERROR && Log.isLoggable(LOG_TAG, Log.WARN)) { Log.w(LOG_TAG, e.getMessage()); } } // The options specified in the Intent (from ParseLoginBuilder) will // override any duplicate options specified in the activity metadata Bundle mergedOptions = new Bundle(); if (activityInfo != null && activityInfo.metaData != null) { mergedOptions.putAll(activityInfo.metaData); } if (getIntent().getExtras() != null) { mergedOptions.putAll(getIntent().getExtras()); } return mergedOptions; } }