/* * Copyright (c) 2004-2009 XMLVM --- An XML-based Programming Language * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * 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, write to the Free Software Foundation, Inc., 675 Mass * Ave, Cambridge, MA 02139, USA. * * For more information, visit the XMLVM Home Page at http://www.xmlvm.org */ package android.view; import org.xmlvm.iphone.CGAffineTransform; import org.xmlvm.iphone.CGRect; import org.xmlvm.iphone.UIApplication; import org.xmlvm.iphone.UIColor; import org.xmlvm.iphone.UIScreen; import org.xmlvm.iphone.UIView; import org.xmlvm.iphone.UIWindow; import android.app.Activity; import android.content.pm.ActivityInfo; import android.graphics.drawable.Drawable; import android.internal.Assert; import android.internal.DecorView; import android.internal.LayoutManager; import android.view.View.MeasureSpec; import android.view.ViewGroup.LayoutParams; import android.widget.FrameLayout; /** * iPhone Implementation of Android's Window class. * * @see http://developer.android.com/reference/android/view/Window.html */ public class Window { public static final int FEATURE_NO_TITLE = 1; private Activity activity; private UIWindow iWindow; private View toast; private FrameLayout internalView; private DecorView decorView; private FrameLayout contentParent; private boolean floating = false; public Window(Activity parent) { this.activity = parent; } public void setContentView(View view) { xmlvmRemoveWindow(); // Set default FrameLayout.LayoutParams if view does not have layout // params if (view.getLayoutParams() == null) { view.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); } // Create UIWindow and transparent internal FrameLayout used to layout // the content views. iWindow = new UIWindow(); iWindow.setBackgroundColor(UIColor.clearColor); internalView = new FrameLayout(activity); internalView.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); internalView.setBackgroundColor(0x80000000); iWindow.addSubview(internalView.xmlvmGetUIView()); // Create DecorView used as the window for all content views int gravity = ((FrameLayout.LayoutParams) view.getLayoutParams()).gravity; decorView = new DecorView(activity); // TODO: Set DecorView's LayoutParams based on Window.isFloating() FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( isFloating() ? LayoutParams.WRAP_CONTENT : LayoutParams.FILL_PARENT, isFloating() ? LayoutParams.WRAP_CONTENT : LayoutParams.FILL_PARENT, gravity); decorView.setLayoutParams(lp); internalView.addView(decorView); // Wrap the provided view with a FrameLayout as Android it does. Android // uses this to layout the window's decoration. We do it the same way to // support all FrameLayout.LayoutParams imposed on the content view. contentParent = new FrameLayout(activity); contentParent.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); contentParent.setBackgroundColor(0x00000000); contentParent.addView(view); decorView.addView(contentParent); adjustFrameSize(); xmlvmSetHidden(false); } public void setContentView(int id) { View v = LayoutManager.getLayout(activity, id, null); setContentView(v); } public void addContentView(View view, ViewGroup.LayoutParams params) { contentParent.addView(view, params); layoutContentView(view); } public void setFlags(int flags, int mask) { int maskedFlags = (flags & mask); if ((maskedFlags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) { UIApplication.sharedApplication().setStatusBarHidden(true); adjustFrameSize(); } } public void setBackgroundDrawableResource(int resId) { if (decorView != null) { decorView.setBackgroundResource(resId); } } public void setBackgroundDrawable(Drawable drawable) { if (decorView != null) { decorView.setBackgroundDrawable(drawable); } } public void xmlvmShowToast(View toast) { Assert.CHECK(this.toast == null); this.toast = toast; layoutContentView(toast); UIView itoast = toast.xmlvmGetUIView(); itoast.setUserInteractionEnabled(false); iWindow.addSubview(itoast); } public void xmlvmRemoveToast() { if (toast == null) return; UIView itoast = toast.xmlvmGetUIView(); itoast.removeFromSuperview(); toast = null; } public void xmlvmSetHidden(boolean flag) { if (iWindow != null) { if (flag) { iWindow.setHidden(true); } else { iWindow.makeKeyAndVisible(); iWindow.setHidden(false); } } } public void xmlvmRemoveWindow() { if (iWindow != null) { xmlvmSetHidden(true); iWindow.xmlvmDestroy(); iWindow = null; internalView.removeAllViews(); internalView = null; decorView.removeAllViews(); decorView = null; contentParent.removeAllViews(); contentParent = null; } } /** * Internal. Not part of Android API. Called whenever the size or * orientation of the top-level window has changed (e.g., when the status * bar is made invisible). */ private void adjustFrameSize() { if (iWindow == null) return; iWindow.setTransform(null); CGRect rect = getCGRect(); iWindow.setFrame(rect); if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { CGAffineTransform rotation = CGAffineTransform .makeRotation((float) ((Math.PI / 180) * 90)); // TODO Translate should be 90, 90 for visible status bar (i.e., // non-fullscreen) CGAffineTransform translation = CGAffineTransform.translate(rotation, 80, 80); iWindow.setTransform(translation); } layoutContentView(internalView); } private void layoutContentView(View view) { if (view.getLayoutParams() == null) { view.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); } int widthMeasureSpec; int heightMeasureSpec; CGRect rect = getCGRect(); LayoutParams lp = view.getLayoutParams(); if (lp == null || lp.width == LayoutParams.FILL_PARENT) { widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) rect.size.width, MeasureSpec.EXACTLY); } else if (lp.width == LayoutParams.WRAP_CONTENT) { widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) rect.size.width, MeasureSpec.AT_MOST); } else { widthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); } if (lp == null || lp.height == LayoutParams.FILL_PARENT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) rect.size.height, MeasureSpec.EXACTLY); } else if (lp.height == LayoutParams.WRAP_CONTENT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) rect.size.height, MeasureSpec.AT_MOST); } else { heightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } view.xmlvmSetMeasureSpec(widthMeasureSpec, heightMeasureSpec); view.requestLayout(); } /** * Internal. Not part of Android API. */ public CGRect getCGRect() { UIScreen screen = UIScreen.mainScreen(); CGRect rect = screen.getApplicationFrame(); if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { float t = rect.size.height; rect.size.height = rect.size.width; rect.size.width = t; } return rect; } /** * @param id * @return */ public View findViewById(int id) { return internalView.findViewById(id); } public WindowManager.LayoutParams getAttributes() { // TODO return proper attributes return new WindowManager.LayoutParams(); } public boolean isFloating() { return floating; } }