/*
* Copyright (C) 2011 The original author or authors.
*
* 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.zapta.apps.maniana.help;
import static com.zapta.apps.maniana.util.Assertions.check;
import static com.zapta.apps.maniana.util.Assertions.checkNotNull;
import java.io.InputStream;
import java.util.Hashtable;
import javax.annotation.Nullable;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.webkit.WebView;
import com.zapta.apps.maniana.R;
import com.zapta.apps.maniana.annotations.ActivityScope;
import com.zapta.apps.maniana.util.DisplayUtil;
import com.zapta.apps.maniana.util.FileUtil;
import com.zapta.apps.maniana.util.FileUtil.FileReadResult;
import com.zapta.apps.maniana.util.FileUtil.FileReadResult.FileReadOutcome;
import com.zapta.apps.maniana.util.LogUtil;
import com.zapta.apps.maniana.util.PackageUtil;
import com.zapta.apps.maniana.util.TextUtil;
/**
* Shows a popup message such as startup splash. The message is taken from an HTML asset page.
*
* @author Tal Dayan.
*/
@ActivityScope
public class PopupMessageActivity extends Activity {
private static final int BORDER_WIDTH_DIP = 5;
private static final String INTENT_MESSAGE_KIND_KEY = "com.zapta.apps.maniana.messageKind";
public static enum MessageKind {
ABOUT("help/about", ".html", true, 0),
NEW_USER("help/new_user_welcome", ".html", false, 0xff00bb00),
WHATS_NEW("help/whats_new", ".html", false, 0xff00ccff),
BACKUP_HELP("help/backup_help", ".html", false, 0xff0000ff);
// TODO(tal): since all messages come from assets, have the names more asset specific.
private final String mAssetRelativeBaseName;
private final String mAssetExtension;
private final boolean mIsFullScreen;
private final int mFrameColor;
private MessageKind(String assetRelativeBaseName, String assetExtension,
boolean isFulLScreen, int frameColor) {
this.mAssetRelativeBaseName = assetRelativeBaseName;
this.mAssetExtension = assetExtension;
this.mIsFullScreen = isFulLScreen;
this.mFrameColor = frameColor;
}
}
// TODO: move to FileUtil?
public final static String ASSETS_BASE_URL = "file:///android_asset/";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
// Get message kind from intent
final MessageKind messageKind = parseMessageKind();
if (messageKind == null) {
finish();
return;
}
if (messageKind.mIsFullScreen) {
onCreateFullScreen(messageKind);
return;
}
onCreateSmallLayout(messageKind);
}
private final void onCreateFullScreen(MessageKind messageKind) {
check(messageKind.mIsFullScreen, messageKind.toString());
setContentView(R.layout.message_full_screen_layout);
final WebView webview = (WebView) findViewById(R.id.message_full_screen_webview);
displayFromAsset(webview, messageKind);
}
private final void onCreateSmallLayout(MessageKind messageKind) {
check(!messageKind.mIsFullScreen, messageKind.toString());
setContentView(R.layout.message_small_layout);
// Set border color and size
// TODO: is there a way to set only the color and use default stroke width?
final View frame = findViewById(R.id.message_small_frame);
final GradientDrawable gradientDrawable = (GradientDrawable) frame.getBackground();
final float density = DisplayUtil.getDensity(this);
final int strokeWidthPixels = (int) ((BORDER_WIDTH_DIP * density) + 0.5f);
gradientDrawable.setStroke(strokeWidthPixels, messageKind.mFrameColor);
final WebView webview = (WebView) findViewById(R.id.message_small_webview);
// NOTE: this stoped working since Android 4.11. The onNewPicture() is not called anymore
// if the frame is invisible.
//
// We enable the message view only after the html page got rendered. This avoids a flicker
// as the views finalize their sizes.
//
// frame.setVisibility(View.INVISIBLE);
// webview.setPictureListener(new PictureListener() {
// public void onNewPicture(WebView view, Picture picture) {
// frame.setVisibility(View.VISIBLE);
// }
// });
displayFromAsset(webview, messageKind);
}
private final void displayFromAsset(WebView webView, MessageKind messageKind) {
// Open HTML assert file. First we try a language specific file and if could
// not open, fail over to the default one in english.
String filePath = null;
InputStream in = null;
final String languageCode = getString(R.string.translation_language_code);
if (!languageCode.equals("en")) {
filePath = messageKind.mAssetRelativeBaseName + "-" + languageCode
+ messageKind.mAssetExtension;
in = FileUtil.openAssert(this, filePath);
}
if (in == null) {
filePath = messageKind.mAssetRelativeBaseName + messageKind.mAssetExtension;
in = FileUtil.openAssert(this, filePath);
}
final FileReadResult fileReadResult = FileUtil.readFileToString(in, filePath);
// TODO: handle this more gracefully?
check(fileReadResult.outcome == FileReadOutcome.READ_OK,
"Error reading asset file: %s, outcome: %s", filePath, fileReadResult.outcome);
final String htmlPage = expandMacros(fileReadResult.content);
webView.loadDataWithBaseURL(ASSETS_BASE_URL + filePath, htmlPage, null, "UTF-8", null);
}
private final String expandMacros(String text) {
if (!TextUtil.constainsMacros(text)) {
return text;
}
final Hashtable<String, Object> macroValues = new Hashtable<String, Object>();
final PackageInfo packageInfo = PackageUtil.getPackageInfo(this);
macroValues.put("version_name", packageInfo.versionName);
return TextUtil.expandMacros(text, macroValues, true);
}
/** Print a log error and return null if not found or an error */
@Nullable
private final MessageKind parseMessageKind() {
// Get message kind from intent
final MessageKind messageKind;
// {
@Nullable
final String messageKindName = getIntent().getExtras().getString(INTENT_MESSAGE_KIND_KEY);
if (messageKindName == null) {
LogUtil.error("Message activity intent has message kind: %s", getIntent());
// finish();
return null;
}
try {
messageKind = MessageKind.valueOf(messageKindName);
} catch (IllegalArgumentException e) {
LogUtil.error("Unknown message kind name [%s] in intent: %s", messageKindName,
getIntent());
// finish();
return null;
}
checkNotNull(messageKind);
return messageKind;
}
/** Create an intent to invoke this activity. */
public static final Intent intentFor(Context callerContext, MessageKind messageKind) {
final Intent intent = new Intent(callerContext, PopupMessageActivity.class);
intent.putExtra(INTENT_MESSAGE_KIND_KEY, messageKind.toString());
return intent;
}
}