/**
* Copyright (c) 2014-present, 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.facebook.internal;
import android.app.Activity;
import android.support.v4.app.Fragment;
import android.util.Log;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookDialog;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import java.util.List;
/**
* com.facebook.internal is solely for the use of other packages within the Facebook SDK for
* Android. Use of any of the classes in this package is unsupported, and they may be modified or
* removed without warning at any time.
*/
public abstract class FacebookDialogBase<CONTENT, RESULT>
implements FacebookDialog<CONTENT, RESULT> {
private static final String TAG = "FacebookDialog";
protected static final Object BASE_AUTOMATIC_MODE = new Object();
private final Activity activity;
private final Fragment fragment;
private List<ModeHandler> modeHandlers;
private int requestCode;
protected FacebookDialogBase(final Activity activity, int requestCode) {
Validate.notNull(activity, "activity");
this.activity = activity;
this.fragment = null;
this.requestCode = requestCode;
}
protected FacebookDialogBase(final Fragment fragment, int requestCode) {
Validate.notNull(fragment, "fragment");
this.fragment = fragment;
this.activity = null;
this.requestCode = requestCode;
if (fragment.getActivity() == null) {
throw new IllegalArgumentException(
"Cannot use a fragment that is not attached to an activity");
}
}
@Override
public final void registerCallback(
final CallbackManager callbackManager,
final FacebookCallback<RESULT> callback) {
if (!(callbackManager instanceof CallbackManagerImpl)) {
throw new FacebookException("Unexpected CallbackManager, " +
"please use the provided Factory.");
}
registerCallbackImpl((CallbackManagerImpl)callbackManager, callback);
}
@Override
public final void registerCallback(
final CallbackManager callbackManager,
final FacebookCallback<RESULT> callback,
final int requestCode) {
setRequestCode(requestCode);
registerCallback(callbackManager, callback);
}
protected abstract void registerCallbackImpl(
final CallbackManagerImpl callbackManager,
final FacebookCallback<RESULT> callback);
/**
* Set the request code for the startActivityForResult call. The requestCode should be
* outside of the range of those reserved for the Facebook SDK
* {@link com.facebook.FacebookSdk#isFacebookRequestCode(int)}.
*
* @param requestCode the request code to use.
*/
protected void setRequestCode(int requestCode) {
if (FacebookSdk.isFacebookRequestCode(requestCode)) {
throw new IllegalArgumentException("Request code " + requestCode +
" cannot be within the range reserved by the Facebook SDK.");
}
this.requestCode = requestCode;
}
/**
* Returns the request code used for this dialog.
*
* @return the request code.
*/
public int getRequestCode() {
return requestCode;
}
@Override
public boolean canShow(CONTENT content) {
return canShowImpl(content, BASE_AUTOMATIC_MODE);
}
// Pass in BASE_AUTOMATIC_MODE when Automatic mode choice is desired
protected boolean canShowImpl(CONTENT content, Object mode) {
boolean anyModeAllowed = (mode == BASE_AUTOMATIC_MODE);
for (ModeHandler handler : cachedModeHandlers()) {
if (!anyModeAllowed && !Utility.areObjectsEqual(handler.getMode(), mode)) {
continue;
}
if (handler.canShow(content)) {
return true;
}
}
return false;
}
@Override
public void show(final CONTENT content) {
showImpl(content, BASE_AUTOMATIC_MODE);
}
// Pass in BASE_AUTOMATIC_MODE when Automatic mode choice is desired
protected void showImpl(final CONTENT content, final Object mode) {
AppCall appCall = createAppCallForMode(content, mode);
if (appCall != null) {
if (fragment != null) {
DialogPresenter.present(appCall, fragment);
} else {
DialogPresenter.present(appCall, activity);
}
} else {
// If we got a null appCall, then the derived dialog code is doing something wrong
String errorMessage = "No code path should ever result in a null appCall";
Log.e(TAG, errorMessage);
if (FacebookSdk.isDebugEnabled()) {
throw new IllegalStateException(errorMessage);
}
}
}
protected Activity getActivityContext() {
if (activity != null) {
return activity;
}
if (fragment != null) {
return fragment.getActivity();
}
return null;
}
private AppCall createAppCallForMode(final CONTENT content, final Object mode) {
boolean anyModeAllowed = (mode == BASE_AUTOMATIC_MODE);
AppCall appCall = null;
for (ModeHandler handler : cachedModeHandlers()) {
if (!anyModeAllowed && !Utility.areObjectsEqual(handler.getMode(), mode)) {
continue;
}
if (!handler.canShow(content)) {
continue;
}
try {
appCall = handler.createAppCall(content);
} catch (FacebookException e) {
appCall = createBaseAppCall();
DialogPresenter.setupAppCallForValidationError(appCall, e);
}
break;
}
if (appCall == null) {
appCall = createBaseAppCall();
DialogPresenter.setupAppCallForCannotShowError(appCall);
}
return appCall;
}
private List<ModeHandler> cachedModeHandlers() {
if (modeHandlers == null) {
modeHandlers = getOrderedModeHandlers();
}
return modeHandlers;
}
protected abstract List<ModeHandler> getOrderedModeHandlers();
protected abstract AppCall createBaseAppCall();
protected abstract class ModeHandler {
/**
* @return An object to signify a specific dialog-mode.
*/
public Object getMode() {
return BASE_AUTOMATIC_MODE;
}
public abstract boolean canShow(final CONTENT content);
public abstract AppCall createAppCall(final CONTENT content);
}
}