/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #filter substitution package @ANDROID_PACKAGE_NAME@; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.MenuItem; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.RelativeLayout; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils; import android.view.animation.Animation; import android.widget.ImageView; import android.view.Display; import android.graphics.Point; import java.net.URL; import java.io.File; import org.mozilla.gecko.GeckoApp; import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoEvent; import org.mozilla.gecko.WebAppAllocator; import org.mozilla.gecko.Tab; import org.mozilla.gecko.Tabs; import org.mozilla.gecko.R; import org.mozilla.gecko.DoorHangerPopup; import org.json.JSONObject; public class WebApp extends GeckoApp { private URL mOrigin; private TextView mTitlebarText = null; private View mTitlebar = null; private static final String LOGTAG = "WebApp"; private View mSplashscreen = null; protected int getIndex() { return 0; } @Override public int getLayout() { return R.layout.web_app; } @Override public boolean hasTabsSideBar() { return false; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); overridePendingTransition(R.anim.grow_fade_in_center, android.R.anim.fade_out); showSplash(); String action = getIntent().getAction(); Bundle extras = getIntent().getExtras(); String title = extras != null ? extras.getString(Intent.EXTRA_SHORTCUT_NAME) : null; setTitle(title != null ? title : "Web App"); mTitlebarText = (TextView)findViewById(R.id.webapp_title); mTitlebar = findViewById(R.id.webapp_titlebar); if (!action.startsWith(ACTION_WEBAPP_PREFIX)) { Log.e(LOGTAG, "WebApp launch, but intent action is " + action + "!"); return; } // Try to use the origin stored in the WebAppAllocator first String origin = WebAppAllocator.getInstance(this).getAppForIndex(getIndex()); try { mOrigin = new URL(origin); } catch (java.net.MalformedURLException ex) { // If that failed fall back to the origin stored in the shortcut Log.i(LOGTAG, "Webapp is not registered with allocator"); try { mOrigin = new URL(getIntent().getData().toString()); } catch (java.net.MalformedURLException ex2) { Log.e(LOGTAG, "Unable to parse intent url: ", ex); } } } @Override protected void initializeChrome(String uri, Boolean isExternalURL) { super.initializeChrome(uri, isExternalURL); Tabs.getInstance().loadUrl(uri, Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_USER_ENTERED | Tabs.LOADURL_PINNED); } private void showSplash() { mSplashscreen = (RelativeLayout) findViewById(R.id.splashscreen); SharedPreferences prefs = getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); // get the favicon dominant color, stored when the app was installed int[] colors = new int[2]; int dominantColor = prefs.getInt(WebAppAllocator.iconKey(getIndex()), -1); // now lighten it, to ensure that the icon stands out in the center float[] f = new float[3]; Color.colorToHSV(dominantColor, f); f[2] = Math.min(f[2]*2, 1.0f); colors[0] = Color.HSVToColor(255, f); // now generate a second, slightly darker version of the same color f[2] *= 0.75; colors[1] = Color.HSVToColor(255, f); // Draw the background gradient GradientDrawable gd = new GradientDrawable(GradientDrawable.Orientation.TL_BR, colors); gd.setGradientType(GradientDrawable.RADIAL_GRADIENT); Display display = getWindowManager().getDefaultDisplay(); gd.setGradientCenter(0.5f, 0.5f); gd.setGradientRadius(Math.max(display.getWidth()/2, display.getHeight()/2)); mSplashscreen.setBackgroundDrawable((Drawable)gd); // look for a logo.png in the profile dir and show it. If we can't find a logo show nothing File profile = getProfile().getDir(); File logoFile = new File(profile, "logo.png"); if (logoFile.exists()) { ImageView image = (ImageView)findViewById(R.id.splashscreen_icon); Drawable d = Drawable.createFromPath(logoFile.getPath()); image.setImageDrawable(d); Animation fadein = AnimationUtils.loadAnimation(this, R.anim.grow_fade_in_center); fadein.setStartOffset(500); fadein.setDuration(1000); image.startAnimation(fadein); } } public String getPackageName() { return "@ANDROID_PACKAGE_NAME@"; } public String getContentProcessName() { return "@MOZ_CHILD_PROCESS_NAME@"; } public String getDefaultUAString() { String deviceType = "Mobile"; if (GeckoAppShell.isTablet()) deviceType = "Tablet"; return "Mozilla/5.0 (Android; " + deviceType + "; rv:@MOZ_APP_VERSION@) Gecko/@MOZ_APP_VERSION@ Firefox/@MOZ_APP_VERSION@"; } public String getUAStringForHost(String host) { // With our standard UA String, we get a 200 response code and // client-side redirect from t.co. This bot-like UA gives us a // 301 response code if ("t.co".equals(host)) return "Redirector/@MOZ_APP_VERSION@ (Android; rv:@MOZ_APP_VERSION@)"; return getDefaultUAString(); } @Override protected String getDefaultProfileName() { String action = getIntent().getAction(); if (!action.startsWith(ACTION_WEBAPP_PREFIX)) { Log.e(LOGTAG, "WebApp launch, but intent action is " + action + "!"); return null; } return "webapp" + action.substring(ACTION_WEBAPP_PREFIX.length()); } @Override public boolean onOptionsItemSelected(MenuItem item) { #ifdef MOZ_PROFILING if (item.getItemId() == R.id.toggle_profiling) { GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("ToggleProfiling", null)); return true; } #endif return super.onOptionsItemSelected(item); } #ifdef MOZ_LINKER_EXTRACT @Override public boolean linkerExtract() { return true; } #endif @Override protected boolean shouldRestoreSession() { return false; } @Override public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) { switch(msg) { case SELECTED: case LOCATION_CHANGE: if (Tabs.getInstance().isSelectedTab(tab)) { try { String title = tab.getURL(); URL page = new URL(title); mTitlebarText.setText(page.getProtocol() + "://" + page.getHost()); if (mOrigin != null && mOrigin.getHost().equals(page.getHost())) mTitlebar.setVisibility(View.GONE); else mTitlebar.setVisibility(View.VISIBLE); } catch (java.net.MalformedURLException ex) { Log.e(LOGTAG, "Unable to parse url: ", ex); } } break; case LOADED: if (mSplashscreen.getVisibility() == View.VISIBLE) { Animation fadeout = AnimationUtils.loadAnimation(this, android.R.anim.fade_out); fadeout.setAnimationListener(new Animation.AnimationListener() { public void onAnimationEnd(Animation animation) { mSplashscreen.setVisibility(View.GONE); } public void onAnimationRepeat(Animation animation) { } public void onAnimationStart(Animation animation) { } }); mSplashscreen.startAnimation(fadeout); } break; case START: if (mSplashscreen.getVisibility() == View.VISIBLE) { View area = findViewById(R.id.splashscreen_progress); area.setVisibility(View.VISIBLE); Animation fadein = AnimationUtils.loadAnimation(this, android.R.anim.fade_in); fadein.setDuration(1000); area.startAnimation(fadein); } break; } super.onTabChanged(tab, msg, data); } protected void connectGeckoLayerClient() { super.connectGeckoLayerClient(); getLayerView().setOverScrollMode(View.OVER_SCROLL_NEVER); } };