package de.blau.android; import java.io.IOException; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.TypedArray; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarDrawerToggle; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.widget.ListView; import de.blau.android.prefs.Preferences; import de.blau.android.util.BugFixedAppCompatActivity; /** * Minimal system for viewing help files * Currently only html format is supported directly * @author simon * */ public class HelpViewer extends BugFixedAppCompatActivity { private static String DEBUG_TAG = HelpViewer.class.getName(); class HelpItem implements Comparable<HelpItem> { boolean displayLanguage = false; String language; int order; String topic; @Override public int compareTo(@NonNull HelpItem another) { if (order < Integer.MAX_VALUE) { if (order > another.order) { return 1; } else if (order < another.order) { return -1; } } return topic.compareTo(another.topic); // sort the rest alphabetically } @Override public String toString() { return topic + (displayLanguage ? " (" + language + ")": ""); } } private static final String TOPIC = "topic"; private WebView helpView; private ActionBarDrawerToggle mDrawerToggle; // drawer that will be our ToC private DrawerLayout mDrawerLayout; private ListView mDrawerList; private ArrayAdapter<HelpItem> tocAdapter; public static void start(@NonNull Context context, @StringRes int topic) { Intent intent = new Intent(context, HelpViewer.class); intent.putExtra(TOPIC, topic); context.startActivity(intent); } @SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { Preferences prefs = new Preferences(this); if (prefs.lightThemeEnabled()) { setTheme(R.style.Theme_customHelpViewer_Light); } super.onCreate(savedInstanceState); int topicId = R.string.help_introduction; Serializable s = getIntent().getSerializableExtra(TOPIC); if ( s != null) { try { topicId = (Integer)s; } catch (Exception e) { Log.e(DEBUG_TAG,"casting topic raised " + e); } } else { Log.d(DEBUG_TAG,"Falling back to default topic"); } String topic = getString(topicId); // this assumes that the resources are the same, which is probably safe setContentView(R.layout.help_drawer); // // Find the toolbar view inside the activity layout // Toolbar toolbar = (Toolbar) findViewById(R.id.helpToolbar); // // Sets the Toolbar to act as the ActionBar for this Activity window. // // Make sure the toolbar exists in the activity and is not null // setSupportActionBar(toolbar); ActionBar actionbar = getSupportActionBar(); if (actionbar == null) { Log.d("HelpViewer", "No actionbar"); // fail? return; } actionbar.setDisplayShowHomeEnabled(true); actionbar.setTitle(getString(R.string.menu_help) + ": " + topic); actionbar.setDisplayShowTitleEnabled(true); actionbar.show(); // add our content FrameLayout fl = (FrameLayout) findViewById(R.id.content_frame); helpView = new WebView(this); WebSettings helpSettings = helpView.getSettings(); helpSettings.setDefaultFontSize(12); helpSettings.setSupportZoom(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { helpSettings.setDisplayZoomControls(false); // don't display +- } else { helpSettings.setBuiltInZoomControls(true); } helpView.setWebViewClient(new HelpViewWebViewClient()); fl.addView(helpView); // set up the drawer mDrawerLayout = (DrawerLayout) findViewById(R.id.help_drawer_layout); mDrawerList = (ListView) findViewById(R.id.help_left_drawer); actionbar.setHomeButtonEnabled(true); actionbar.setDisplayHomeAsUpEnabled(true); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.okay, R.string.okay); mDrawerToggle.setDrawerIndicatorEnabled(true); mDrawerLayout.addDrawerListener(mDrawerToggle); try { List<String> defaultList = Arrays.asList(getResources().getAssets().list("help/" + Locale.getDefault().getLanguage())); List<String> enList = Arrays.asList(getResources().getAssets().list("help/en")); String defaultLanguage = Locale.getDefault().getLanguage(); TypedArray tocRes = getResources().obtainTypedArray(R.array.help_tableofcontents); HashMap <String,HelpItem> tocList = new HashMap<String,HelpItem>(); for (int i=0;i<tocRes.length();i++) { String tocTopic = tocRes.getString(i); // Log.d("HelpViewer", "TOC " + tocTopic); if (defaultList.contains(tocTopic + ".html")) { // Log.d("HelpViewer", "TOC " + locale + " " + tocTopic); HelpItem h = new HelpItem(); h.language = defaultLanguage; h.topic = tocTopic; h.order = i; if (!tocList.containsKey(h.topic)) { tocList.put(h.topic,h); } } else if (enList.contains(tocTopic + ".html")){ // Log.d("HelpViewer", "TOC en " + tocTopic); HelpItem h = new HelpItem(); h.language = "en"; h.displayLanguage = true; h.topic = tocTopic; h.order = i; if (!tocList.containsKey(h.topic)) { tocList.put(h.topic,h); } } } tocRes.recycle(); List<HelpItem> items = new ArrayList<HelpItem>(tocList.values()); Collections.sort(items); HelpItem[] toc = new HelpItem[items.size()]; items.toArray(toc); tocAdapter = new ArrayAdapter<HelpItem>(this, R.layout.help_drawer_item,R.id.help_drawer_item, toc); mDrawerList.setAdapter(tocAdapter); mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); String helpFile = "help/" + Locale.getDefault().getLanguage() + "/" + topic + ".html"; Log.d("HelpViewer","1 Looking for help file: " + helpFile); if (!defaultList.contains(topic + ".html")) { helpFile = "help/en/" + topic + ".html"; if (!enList.contains(topic + ".html")) { helpFile = "help/en/no_help.html"; mDrawerLayout.openDrawer(mDrawerList); } } helpView.loadUrl("file:///android_asset/" + helpFile); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Creates the menu from the XML file "main_menu.xml".<br> {@inheritDoc} */ @Override public boolean onCreateOptionsMenu(final Menu menu) { final MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.help_menu, menu); return true; } @Override public boolean onOptionsItemSelected(final MenuItem item) { if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } Log.d(DEBUG_TAG, "onOptionsItemSelected"); switch (item.getItemId()) { case R.id.help_menu_back: if (helpView.canGoBack()) { helpView.goBack(); // getSupportActionBar().setTitle(getString(R.string.menu_help) + ": " + getTopic(helpView.getUrl())); } else { onBackPressed(); // return to caller } return true; case R.id.help_menu_forward: if (helpView.canGoForward()) { helpView.goForward(); // getSupportActionBar().setTitle(getString(R.string.menu_help) + ": " + getTopic(helpView.getUrl())); } return true; } return false; } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { HelpItem helpItem = tocAdapter.getItem(position); helpView.loadUrl("file:///android_asset/help/" + helpItem.language + "/" + helpItem.topic +".html"); mDrawerLayout.closeDrawer(mDrawerList); mDrawerList.setSelected(false); getSupportActionBar().setTitle(getString(R.string.menu_help) + ": " + helpItem.topic); } } private class HelpViewWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // WebViewClient is slightly bizarre because there is no way to indicate to the webview that you would like // if to process the url in its default way, its either handling it yourself or loading it directly into the // webview if (url != null && url.startsWith("file:")) { Log.d("HelpViewer","orig " + url); getSupportActionBar().setTitle(getString(R.string.menu_help) + ": " + getTopic(url)); if (url.endsWith(".md")) { // on device we have pre-generated html url = url.substring(0,url.length()-".md".length()) + ".html"; Log.d("HelpViewer","new " + url); } view.loadUrl(url); return true; } else { view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); return true; } } @Override public void onPageFinished (WebView view, String url) { super.onPageFinished(view, url); if (url.startsWith("file:")) { getSupportActionBar().setTitle(getString(R.string.menu_help) + ": " + getTopic(url)); } } } private String getTopic(String url) { try { url = URLDecoder.decode(url,"UTF-8"); } catch (UnsupportedEncodingException e) { return "Error, got: " + url; } int lastSlash = url.lastIndexOf('/'); int lastDot = url.lastIndexOf('.'); if (lastSlash < 0 || lastDot < 0) { return "Error, got: " + url; } return url.substring(lastSlash+1,lastDot); } }