/*
* Copyright 2016 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package flow.sample.orientation;
import android.app.Activity;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import flow.Dispatcher;
import flow.Traversal;
import flow.TraversalCallback;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
final class OrientationSampleDispatcher implements Dispatcher {
/**
* Using a static for this is a fragile hack for demo purposes. In
* real life you'd want something hanging off of a custom application
* class--perhaps a Mortar activity scope.
*/
private static TraversalCallback hangingCallback;
public static void finishPendingTraversal() {
if (hangingCallback != null) {
// The previous dispatcher was unable to finish its traversal because it
// required a configuration change. Let flow know that we're awake again
// in our new orientation and that traversal is done.
TraversalCallback ref = hangingCallback;
hangingCallback = null;
ref.onTraversalCompleted();
}
}
private final Activity activity;
OrientationSampleDispatcher(Activity activity) {
this.activity = activity;
}
@Override
public void dispatch(@NonNull Traversal traversal, @NonNull TraversalCallback callback) {
Log.d("BasicDispatcher", "dispatching " + traversal);
final OrientationSampleScreen destScreen = traversal.destination.top();
final boolean incomingNeedsLock = destScreen.requiresLandscape();
final boolean waitForOrientationChange = incomingNeedsLock && requestLandscapeLock();
if (waitForOrientationChange) {
// There is about to be an orientation change, which means there will
// soon be a new activity and a new dispatcher. Let them complete
// this traversal, so that we don't try to show a landscape-only screen
// in portrait.
hangingCallback = callback;
} else {
ViewGroup frame = (ViewGroup) activity.findViewById(R.id.basic_activity_frame);
View destView = LayoutInflater.from(traversal.createContext(destScreen, activity)) //
.inflate(destScreen.getLayoutId(), frame, false);
frame.removeAllViews();
frame.addView(destView);
if (!incomingNeedsLock) {
requestUnlock();
}
callback.onTraversalCompleted();
}
}
/**
* Returns true if we've requested a lock and are expecting an orientation change
* as a result.
*/
boolean requestLandscapeLock() {
int requestedOrientation = activity.getRequestedOrientation();
if (requestedOrientation == SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
// We're already locked.
return false;
}
activity.setRequestedOrientation(SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
// We've requested a lock, but there will only be an orientation change
// if we're not already landscape.
return isPortrait();
}
void requestUnlock() {
activity.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
}
boolean isPortrait() {
return activity.getResources().getBoolean(R.bool.is_portrait);
}
}