/*******************************************************************************
* Copyright 2012-present Pixate, 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 com.pixate.freestyle.styling.media;
import java.util.HashMap;
import java.util.Map;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Point;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import com.pixate.freestyle.cg.math.PXDimension;
/**
* Named media expression.<br>
* TODO - This class needs a lot of testing
*/
public class PXNamedMediaExpression implements PXMediaExpression {
private interface PXNamedMediaExpressionHandler {
boolean getValue(Context context, PXNamedMediaExpression expression);
}
private static Map<String, PXNamedMediaExpressionHandler> handlers;
static {
handlers = new HashMap<String, PXNamedMediaExpression.PXNamedMediaExpressionHandler>();
handlers.put("orientation", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_90:
case Surface.ROTATION_270:
return "landscape".equals(expression.getValue().toString());
case Surface.ROTATION_0:
case Surface.ROTATION_180:
return "portrait".equals(expression.getValue().toString());
default:
return false;
}
}
});
handlers.put("device", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
// Seems to work well in detecting an emulator
return Build.FINGERPRINT.indexOf("generic") == -1;
}
});
handlers.put("device-width", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
// TODO - Test this and anything else here that is calling the
// getSize
Point size = getSize(context);
return size.x == expression.getFloatValue(context);
}
});
handlers.put("min-device-width", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
Point size = getSize(context);
return size.y >= expression.getFloatValue(context);
}
});
handlers.put("max-device-width", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
Point size = getSize(context);
return size.x <= expression.getFloatValue(context);
}
});
handlers.put("device-height", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
Point size = getSize(context);
return size.y == expression.getFloatValue(context);
}
});
handlers.put("min-device-height", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
Point size = getSize(context);
return size.y >= expression.getFloatValue(context);
}
});
handlers.put("max-device-height", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
Point size = getSize(context);
return size.y <= expression.getFloatValue(context);
}
});
handlers.put("scale", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
DisplayMetrics metrics = getDisplayMetrics(context);
// TODO - Test this and anything else that reads the density
return metrics.density == expression.getFloatValue(context);
}
});
handlers.put("min-scale", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
DisplayMetrics metrics = getDisplayMetrics(context);
return metrics.density >= expression.getFloatValue(context);
}
});
handlers.put("max-scale", new PXNamedMediaExpressionHandler() {
public boolean getValue(Context context, PXNamedMediaExpression expression) {
DisplayMetrics metrics = getDisplayMetrics(context);
return metrics.density <= expression.getFloatValue(context);
}
});
}
private String name;
private Object value;
/**
* Constructs a new PXNamedMediaExpression
*
* @param name
* @param value
*/
public PXNamedMediaExpression(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
private float getFloatValue(Context context) {
if (value instanceof Number) {
return ((Number) value).floatValue();
} else if (value instanceof String) {
return Float.parseFloat(value.toString());
} else if (value instanceof PXDimension) {
PXDimension dimension = (PXDimension) value;
if (dimension.isLength()) {
DisplayMetrics metrics = getDisplayMetrics(context);
return dimension.points(metrics).getNumber();
} else {
return 0.0f;
}
} else {
return 0.0f;
}
}
/*
* (non-Javadoc)
* @see
* com.pixate.freestyle.styling.media.PXMediaExpression#matches(android.content
* .Context)
*/
public boolean matches(Context context) {
PXNamedMediaExpressionHandler handler = handlers.get(name);
return handler != null ? handler.getValue(context, this) : false;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
if (value != null) {
return String.format("(%s:%s)", name, value);
} else {
return String.format("(%s)", name);
}
}
private static Point getSize(Context context) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point size = new Point();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
getRealSizeHCMR1(display, size);
} else {
getRealSize(display, size);
}
return size;
}
private static DisplayMetrics getDisplayMetrics(Context context) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
return metrics;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void getRealSize(Display display, Point size) {
display.getRealSize(size);
}
private static void getRealSizeHCMR1(Display display, Point size) {
Class<?> clazz = display.getClass();
try {
size.x = (Integer) clazz.getMethod("getRawWidth").invoke(display);
size.y = (Integer) clazz.getMethod("getRawHeight").invoke(display);
return;
} catch (Exception e) {
// This would be odd given our minSdkVersion requirements.
// Fall back to the really old way to do this.
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
size.x = metrics.widthPixels;
size.y = metrics.heightPixels;
}
}
}