Backported the Android app to API 9. See Bug #783 for more details.

This commit is contained in:
Rashiq Ahmad 2013-12-25 20:01:52 +01:00
parent 934da9d251
commit 17190d8770
29 changed files with 937 additions and 501 deletions

View File

@ -15,10 +15,11 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-sdk
android:minSdkVersion="11"
android:minSdkVersion="9"
android:targetSdkVersion="19"/>
<application
android:icon="@drawable/kiwix_icon"
android:theme="@style/Theme.AppCompat"
android:label="@string/app_name"
android:allowBackup="true">
<activity
@ -42,7 +43,7 @@
<data android:mimeType="*/*"/>
</intent-filter>
</activity>
<activity android:name=".KiwixSettings">
<activity android:name=".KiwixSettingsActivity">
</activity>
<provider

View File

@ -11,8 +11,13 @@ buildscript {
apply plugin: 'android'
repositories {
mavenCentral()
}
dependencies {
compile 'com.android.support:support-v4:19.0.0'
compile 'com.android.support:appcompat-v7:19.0.0'
compile files("$buildDir/native-libs/native-libs.jar")
}
@ -22,7 +27,7 @@ android {
buildToolsVersion "19"
defaultConfig {
minSdkVersion 11
minSdkVersion 9
targetSdkVersion 19
}

View File

@ -1,14 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-14

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -28,7 +28,7 @@
android:inputType="text|textCapWords"
android:maxLines="1"
android:background="@android:color/background_dark"
android:textColor="@android:color/primary_text_dark"/>
android:textColor="@android:color/white"/>
</LinearLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:textColor="@android:color/black"
android:minHeight="?android:attr/listPreferredItemHeight"/>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/edit"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:scrollHorizontally="true"
android:inputType="text"
android:hint="@string/search_label"
android:imeOptions="actionDone|flagNoExtractUi|flagNoFullscreen"
android:layout_marginRight="10dip"/>
</LinearLayout>

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_rescan_fs"
android:icon="@drawable/action_refresh"
android:title="@string/menu_rescan_fs"
android:showAsAction="always"/>
app:showAsAction="always"/>
</menu>

View File

@ -1,81 +1,82 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_search"
android:icon="@drawable/action_search"
android:title="@string/menu_search"
android:visible="false"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_back"
android:title="@string/menu_back"
android:icon="@drawable/navigation_back"
android:visible="false"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_forward"
android:title="@string/menu_forward"
android:icon="@drawable/navigation_forward"
android:visible="false"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_randomarticle"
android:icon="@drawable/action_randomarticle"
android:title="@string/menu_randomarticle"
android:visible="false"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_home"
android:title="@string/menu_home"
android:icon="@drawable/action_home"
android:visible="false"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_openfile"
android:title="@string/menu_openfile"
android:icon="@drawable/device_access_sd_storage"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_searchintext"
android:icon="@drawable/action_search"
android:title="@string/menu_searchintext"
android:visible="false"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_fullscreen"
android:icon="@drawable/action_search"
android:title="@string/menu_fullscreen"
android:visible="false"
android:showAsAction="never"/>
app:showAsAction="never"/>
<item
android:id="@+id/menu_settings"
android:title="@string/menu_settings"
android:icon="@drawable/navigation_forward"
android:showAsAction="never"/>
app:showAsAction="never"/>
<item
android:id="@+id/menu_help"
android:title="@string/menu_help"
android:icon="@drawable/action_help"
android:showAsAction="never"/>
app:showAsAction="never"/>
<item
android:id="@+id/menu_share"
android:title="@string/menu_share"
android:icon="@drawable/action_share"
android:showAsAction="ifRoom"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_exit"
android:title="@string/menu_exit"
android:showAsAction="never"/>
app:showAsAction="never"/>
</menu>

28
res/menu/webview_menu.xml Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/find_prev"
android:icon="@drawable/ic_find_previous_holo_dark"
app:showAsAction="always"/>
<item
android:id="@+id/find_next"
android:icon="@drawable/ic_find_next_holo_dark"
app:showAsAction="always"/>
</menu>

View File

@ -54,4 +54,6 @@
<string name="share_via">Share via</string>
<string name="pref_language_title">Language</string>
<string name="pref_language_chooser">Choose a language</string>
<string name="delete_tab_title">Delete Tab</string>
<string name="delete_tab_message">Do you want to delete this tab?</string>
</resources>

1
settings.gradle Normal file
View File

@ -0,0 +1 @@
include ':android'

View File

@ -0,0 +1,37 @@
/*
* Copyright 2013 Rashiq Ahmad <rashiq.z@gmail.com>
*
* 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 3 of the License, or
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.kiwix.kiwixmobile;
import android.os.Build;
public class BackwardsCompatibilityTools {
public static final boolean newApi() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
public static final boolean equalsOrNewThanApi(int api) {
return Build.VERSION.SDK_INT >= api;
}
}

View File

@ -0,0 +1,209 @@
/*
* Copyright 2013 Rashiq Ahmad <rashiq.z@gmail.com>
*
* 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 3 of the License, or
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.kiwix.kiwixmobile;
import android.content.Context;
import android.support.v7.view.ActionMode;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.EditText;
import java.lang.reflect.Method;
public class CompatFindActionModeCallback implements ActionMode.Callback, TextWatcher, View.OnClickListener {
public boolean mIsActive;
private View mCustomView;
private EditText mEditText;
private WebView mWebView;
private InputMethodManager mInput;
private boolean mMatchesFound;
private ActionMode mActionMode;
public CompatFindActionModeCallback(Context context) {
mCustomView = LayoutInflater.from(context).inflate(R.layout.webview_find, null);
mEditText = (EditText) mCustomView.findViewById(R.id.edit);
mEditText.setOnClickListener(this);
mInput = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
mIsActive = false;
setText("");
}
public void setActive() {
mIsActive = true;
}
public void finish() {
mActionMode.finish();
mWebView.clearMatches();
}
// Place text in the text field so it can be searched for. Need to press
// the find next or find previous button to find all of the matches.
public void setText(String text) {
mEditText.setText(text);
Spannable span = mEditText.getText();
int length = span.length();
// Ideally, we would like to set the selection to the whole field,
// but this brings up the Text selection CAB, which dismisses this
// one.
Selection.setSelection(span, length, length);
// Necessary each time we set the text, so that this will watch
// changes to it.
span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
mMatchesFound = false;
}
// Set the WebView to search. Must be non null, and set before calling startActionMode.
public void setWebView(WebView webView) {
if (null == webView) {
throw new AssertionError("WebView supplied to CompatFindActionModeCallback cannot be null");
}
mWebView = webView;
}
// Move the highlight to the next match.
// If true, find the next match further down in the document.
// If false, find the previous match, up in the document.
private void findNext(boolean next) {
if (mWebView == null) {
throw new AssertionError("No WebView for CompatFindActionModeCallback::findNext");
}
mWebView.findNext(next);
}
// Highlight all the instances of the string from mEditText in mWebView.
public void findAll() {
if (mWebView == null) {
throw new AssertionError("No WebView for CompatFindActionModeCallback::findAll");
}
CharSequence find = mEditText.getText();
if (find.length() == 0) {
mWebView.clearMatches();
mMatchesFound = false;
mWebView.findAll(null);
} else {
mMatchesFound = true;
mWebView.findAll(find.toString());
// Enable word highlighting with reflection
try {
for (Method ms : WebView.class.getDeclaredMethods()) {
if (ms.getName().equals("setFindIsUp")) {
ms.setAccessible(true);
ms.invoke(mWebView, true);
break;
}
}
} catch (Exception ignored) {
}
}
}
// Show on screen keyboard
public void showSoftInput() {
mInput.showSoftInput(mEditText, 0);
}
@Override
public void onClick(View v) {
findNext(true);
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setCustomView(mCustomView);
mode.getMenuInflater().inflate(R.menu.webview_menu, menu);
mActionMode = mode;
Editable edit = mEditText.getText();
Selection.setSelection(edit, edit.length());
mMatchesFound = false;
mEditText.requestFocus();
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
mIsActive = false;
mWebView.clearMatches();
mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (mWebView == null) {
throw new AssertionError("No WebView for CompatFindActionModeCallback::onActionItemClicked");
}
mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
switch (item.getItemId()) {
case R.id.find_prev:
findNext(false);
break;
case R.id.find_next:
findNext(true);
break;
default:
return false;
}
return true;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Does nothing. Needed to implement TextWatcher.
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
findAll();
}
@Override
public void afterTextChanged(Editable s) {
// Does nothing. Needed to implement TextWatcher.
}
}

View File

@ -19,20 +19,23 @@
package org.kiwix.kiwixmobile;
import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
@ -44,15 +47,18 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import java.util.ArrayList;
public class KiwixMobileActivity extends FragmentActivity implements ActionBar.TabListener,
View.OnLongClickListener, View.OnDragListener, KiwixMobileFragment.FragmentCommunicator {
import static org.kiwix.kiwixmobile.BackwardsCompatibilityTools.equalsOrNewThanApi;
import static org.kiwix.kiwixmobile.BackwardsCompatibilityTools.newApi;
public class KiwixMobileActivity extends ActionBarActivity implements ActionBar.TabListener,
View.OnLongClickListener, KiwixMobileFragment.FragmentCommunicator {
public static ArrayList<State> mPrefState;
@ -66,6 +72,8 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
private KiwixMobileFragment mCurrentFragment;
private View.OnDragListener mOnDragListener;
private int mNumberOfTabs = 0;
private int mCurrentDraggedTab;
@ -74,29 +82,38 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
private int mTabsHeight;
private CompatFindActionModeCallback mCompatCallback;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_PROGRESS);
setProgressBarVisibility(true);
handleLocaleCheck();
setContentView(R.layout.viewpager);
// Set an OnDragListener on the entire View. Now we can track, if the user drags the
// Tab outside the View
getWindow().getDecorView().setOnDragListener(this);
// Set an OnDragListener on the entire View. Now we can track,
// if the user drags the Tab outside the View
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setUpOnDragListener();
getWindow().getDecorView().setOnDragListener(mOnDragListener);
}
mViewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mActionBar = getActionBar();
mActionBar = getSupportActionBar();
mPrefState = new ArrayList<State>();
mCompatCallback = new CompatFindActionModeCallback(this);
mIsFullscreenOpened = false;
setUpViewPagerAndActionBar();
@ -107,7 +124,7 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
private void setUpViewPagerAndActionBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
if (equalsOrNewThanApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)) {
mActionBar.setHomeButtonEnabled(false);
}
@ -154,6 +171,73 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
});
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setUpOnDragListener() {
mOnDragListener = new View.OnDragListener() {
// Delete the current Tab, that is being dragged, if it hits the bounds of the Screen
@Override
public boolean onDrag(View v, DragEvent event) {
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
// Get the height of the title bar
final int titleBarHeight;
switch (displaymetrics.densityDpi) {
case DisplayMetrics.DENSITY_HIGH:
titleBarHeight = 48;
break;
case DisplayMetrics.DENSITY_MEDIUM:
titleBarHeight = 32;
break;
case DisplayMetrics.DENSITY_LOW:
titleBarHeight = 24;
break;
default:
titleBarHeight = 0;
}
// Get the width and height of the screen
final int screenHeight = displaymetrics.heightPixels;
final int screenWidth = displaymetrics.widthPixels;
// Get the current position of the View, that is being dragged
final int positionX = (int) event.getX();
final int positionY = (int) event.getY();
if (event.getAction() == DragEvent.ACTION_DRAG_EXITED) {
removeTabAt(mCurrentDraggedTab);
return true;
}
if (event.getAction() == DragEvent.ACTION_DROP) {
// Does it hit the boundries on the x-axis?
if ((positionX > screenWidth - (0.25 * mTabsWidth)) ||
(positionX < (0.25 * mTabsWidth))) {
Log.i("kiwix", "Dragged out");
removeTabAt(mCurrentDraggedTab);
}
// Does it hit the boundries on the y-axis?
else if ((positionY > screenHeight - (0.25 * mTabsHeight)) ||
((positionY - titleBarHeight) < (0.5 * mTabsHeight))) {
Log.i("kiwix", "Dragged out");
removeTabAt(mCurrentDraggedTab);
}
return true;
}
return false;
}
};
}
// Reset the Locale and change the font of all TextViews and its subclasses, if necessary
private void handleLocaleCheck() {
LanguageUtils.handleLocaleChange(this);
@ -176,13 +260,10 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
mCurrentFragment = getCurrentVisibleFragment();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
switch (item.getItemId()) {
case R.id.menu_home:
case android.R.id.home:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
mCurrentFragment.openMainPage();
break;
@ -195,18 +276,18 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
break;
case R.id.menu_searchintext:
mCurrentFragment.webView.showFindDialog("", true);
break;
mCompatCallback.setActive();
mCompatCallback.setWebView(mCurrentFragment.webView);
mCompatCallback.showSoftInput();
startSupportActionMode(mCompatCallback);
case R.id.menu_forward:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
if (mCurrentFragment.webView.canGoForward()) {
mCurrentFragment.webView.goForward();
}
break;
case R.id.menu_back:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
if (mCurrentFragment.webView.canGoBack()) {
mCurrentFragment.menu.findItem(R.id.menu_forward).setVisible(true);
mCurrentFragment.webView.goBack();
@ -214,7 +295,6 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
break;
case R.id.menu_randomarticle:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
mCurrentFragment.openRandomArticle();
break;
@ -223,22 +303,18 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
break;
case R.id.menu_help:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
mCurrentFragment.showWelcome();
break;
case R.id.menu_openfile:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
mCurrentFragment.selectZimFile();
break;
case R.id.menu_exit:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
finish();
break;
case R.id.menu_settings:
imm.hideSoftInputFromWindow(mCurrentFragment.articleSearchtextView.getWindowToken(), 0);
// Display the fragment as the main content.
mCurrentFragment.selectSettings();
break;
@ -270,7 +346,7 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
private void openFullScreen() {
mCurrentFragment = getCurrentVisibleFragment();
getActionBar().hide();
getSupportActionBar().hide();
mCurrentFragment.exitFullscreenButton.setVisibility(View.VISIBLE);
mCurrentFragment.menu.findItem(R.id.menu_fullscreen)
.setTitle(getResources().getString(R.string.menu_exitfullscreen));
@ -284,7 +360,7 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
private void closeFullScreen() {
mCurrentFragment = getCurrentVisibleFragment();
getActionBar().show();
getSupportActionBar().show();
mCurrentFragment.menu.findItem(R.id.menu_fullscreen)
.setTitle(getResources().getString(R.string.menu_fullscreen));
mCurrentFragment.exitFullscreenButton.setVisibility(View.INVISIBLE);
@ -298,13 +374,22 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mCurrentFragment = getCurrentVisibleFragment();
// Finish the search functionality on API 11<
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mCompatCallback.mIsActive) {
mCompatCallback.finish();
return true;
}
}
// handle the back button for the WebView in the current Fragment
mCurrentFragment = getCurrentVisibleFragment();
mCurrentFragment.onKeyDown(keyCode, event);
return true;
}
return super.onKeyDown(keyCode, event);
}
@ -332,7 +417,7 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
// current tab would throw a NullPointerException, if the app were in landscape mode and
// therefore possibly in NAVIGATION_MODE_LIST mode
if (mActionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) {
getActionBar().getSelectedTab().setText(title);
getSupportActionBar().getSelectedTab().setText(title);
}
if (mPrefState.size() != 0) {
if (mPrefState.get(position).hasToBeRefreshed()) {
@ -482,14 +567,14 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
mCurrentFragment = getCurrentVisibleFragment();
String title = getResources().getString(R.string.app_name);
if (mCurrentFragment.webView.getTitle() != null &&
!mCurrentFragment.webView.getTitle().isEmpty()) {
if (mCurrentFragment.webView.getTitle() != null
&& !mCurrentFragment.webView.getTitle().isEmpty()) {
title = mCurrentFragment.webView.getTitle();
}
// Set the title for the selected Tab
if (mActionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) {
getActionBar().getSelectedTab().setText(title);
getSupportActionBar().getSelectedTab().setText(title);
}
}
@ -517,16 +602,28 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
// This method gets a reference to the fragment, that is currently visible in the ViewPager
private KiwixMobileFragment getCurrentVisibleFragment() {
return ((KiwixMobileFragment) mViewPagerAdapter.
getFragmentAtPosition(mViewPager.getCurrentItem()));
return ((KiwixMobileFragment) mViewPagerAdapter.getFragmentAtPosition(mViewPager.getCurrentItem()));
}
@Override
public boolean onLongClick(View v) {
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
mCurrentDraggedTab = (Integer) v.getTag(R.id.action_bar_tab_id);
if (newApi()) {
onLongClickOperation(v);
} else {
compatOnLongClickOperation();
}
return true;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void onLongClickOperation(View v) {
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
mTabsWidth = v.getWidth();
mTabsHeight = v.getHeight();
@ -535,69 +632,21 @@ public class KiwixMobileActivity extends FragmentActivity implements ActionBar.T
ClipData data = ClipData.newPlainText("", "");
v.startDrag(data, shadowBuilder, v, 0);
return true;
}
// Delete the current Tab, that is being dragged, if it hits the bounds of the Screen
@Override
public boolean onDrag(View v, DragEvent event) {
private void compatOnLongClickOperation() {
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
// Get the height of the title bar
final int titleBarHeight;
switch (displaymetrics.densityDpi) {
case DisplayMetrics.DENSITY_HIGH:
titleBarHeight = 48;
break;
case DisplayMetrics.DENSITY_MEDIUM:
titleBarHeight = 32;
break;
case DisplayMetrics.DENSITY_LOW:
titleBarHeight = 24;
break;
default:
titleBarHeight = 0;
}
// Get the width and height of the screen
final int screenHeight = displaymetrics.heightPixels;
final int screenWidth = displaymetrics.widthPixels;
// Get the current position of the View, that is being dragged
final int positionX = (int) event.getX();
final int positionY = (int) event.getY();
if (event.getAction() == DragEvent.ACTION_DRAG_EXITED) {
removeTabAt(mCurrentDraggedTab);
return true;
}
if (event.getAction() == DragEvent.ACTION_DROP) {
// Does it hit the boundries on the x-axis?
if ((positionX > screenWidth - (0.25 * mTabsWidth)) ||
(positionX < (0.25 * mTabsWidth))) {
Log.i("kiwix", "Dragged out");
dialog.setTitle(getString(R.string.delete_tab_title));
dialog.setMessage(getString(R.string.delete_tab_message));
dialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
removeTabAt(mCurrentDraggedTab);
}
// Does it hit the boundries on the y-axis?
else if ((positionY > screenHeight - (0.25 * mTabsHeight)) ||
((positionY - titleBarHeight) < (0.5 * mTabsHeight))) {
Log.i("kiwix", "Dragged out");
removeTabAt(mCurrentDraggedTab);
}
return true;
}
return false;
});
dialog.setNegativeButton(android.R.string.no, null);
dialog.show();
}
public class State {

View File

@ -20,6 +20,7 @@
package org.kiwix.kiwixmobile;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
@ -32,6 +33,7 @@ import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@ -39,6 +41,7 @@ import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
@ -85,6 +88,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import static org.kiwix.kiwixmobile.BackwardsCompatibilityTools.newApi;
public class KiwixMobileFragment extends Fragment {
public static final String TAG_KIWIX = "kiwix";
@ -183,14 +188,16 @@ public class KiwixMobileFragment extends Fragment {
setUpWebView();
setUpTabDeleteCross();
setUpArticleSearchTextView(savedInstanceState);
loadPrefs();
manageExternalLaunchAndRestoringViewState(savedInstanceState);
if (newApi()) {
setUpTabDeleteCross();
}
return root;
}
@ -296,8 +303,8 @@ public class KiwixMobileFragment extends Fragment {
if (event.getAction() != MotionEvent.ACTION_UP) {
return false;
}
if (event.getX() > articleSearchtextView.getWidth() - articleSearchtextView.getPaddingRight()
- mClearIcon.getIntrinsicWidth()) {
if (event.getX() > articleSearchtextView.getWidth()
- articleSearchtextView.getPaddingRight() - mClearIcon.getIntrinsicWidth()) {
articleSearchtextView.setText("");
articleSearchtextView.setCompoundDrawables(mSearchIcon, null, null, null);
}
@ -316,8 +323,7 @@ public class KiwixMobileFragment extends Fragment {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
articleSearchtextView.setCompoundDrawables(mSearchIcon, null,
articleSearchtextView.getText().toString().equals("") ? null : mClearIcon,
null);
articleSearchtextView.getText().toString().equals("") ? null : mClearIcon, null);
}
@Override
@ -330,15 +336,19 @@ public class KiwixMobileFragment extends Fragment {
});
// Create the adapter and set it to the AutoCompleteTextView
adapter = new AutoCompleteAdapter(getActivity(),
android.R.layout.simple_list_item_1);
if (newApi()) {
adapter = new AutoCompleteAdapter(getActivity(), android.R.layout.simple_list_item_1);
} else {
adapter = new AutoCompleteAdapter(getActivity(), R.layout.simple_list_item);
}
articleSearchtextView.setAdapter(adapter);
articleSearchtextView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
InputMethodManager imm = (InputMethodManager)
getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(articleSearchtextView.getWindowToken(), 0);
articleSearchtextView.setText(parent.getItemAtPosition(position).toString());
openArticleFromSearch();
@ -347,8 +357,7 @@ public class KiwixMobileFragment extends Fragment {
articleSearchtextView.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
return openArticleFromSearch();
}
});
@ -356,6 +365,7 @@ public class KiwixMobileFragment extends Fragment {
articleSearchtextView.setInputType(InputType.TYPE_CLASS_TEXT);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setUpTabDeleteCross() {
mTabDeleteCross.setOnDragListener(new View.OnDragListener() {
@ -618,7 +628,7 @@ public class KiwixMobileFragment extends Fragment {
}
break;
case PREFERENCES_REQUEST_CODE:
if (resultCode == KiwixSettings.RESULT_RESTART) {
if (resultCode == KiwixSettingsActivity.RESULT_RESTART) {
getActivity().finish();
startActivity(new Intent(getActivity(), KiwixMobileActivity.class));
}
@ -671,8 +681,7 @@ public class KiwixMobileFragment extends Fragment {
// Pinch to zoom
// This seems to suffer from a bug in Android. If you set to "false" this only apply after a restart of the app.
Log.d(TAG_KIWIX, "pref_zoom_enabled value (" + pref_zoom_enabled + ")");
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDisplayZoomControls(pref_zoom_enabled);
webView.disableZoomControlls(pref_zoom_enabled);
if (!isBacktotopEnabled) {
mBackToTopButton.setVisibility(View.INVISIBLE);
@ -699,7 +708,7 @@ public class KiwixMobileFragment extends Fragment {
}
public void selectSettings() {
Intent i = new Intent(getActivity(), KiwixSettings.class);
Intent i = new Intent(getActivity(), KiwixSettingsActivity.class);
startActivityForResult(i, PREFERENCES_REQUEST_CODE);
}
@ -716,8 +725,8 @@ public class KiwixMobileFragment extends Fragment {
// Move cursor to end
articleSearchtextView.setSelection(articleSearchtextView.getText().length());
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}
@ -747,7 +756,8 @@ public class KiwixMobileFragment extends Fragment {
if (file.exists()) {
if (ZimContentProvider.setZimFile(file.getAbsolutePath()) != null) {
getActivity().getActionBar().setSubtitle(ZimContentProvider.getZimFileTitle());
((ActionBarActivity) getActivity()).getSupportActionBar()
.setSubtitle(ZimContentProvider.getZimFileTitle());
// Apparently with webView.clearHistory() only history before currently (fully)
// loaded page is cleared -> request clear, actual clear done after load.
@ -1060,10 +1070,9 @@ public class KiwixMobileFragment extends Fragment {
failingUrl);
// TODO apparently screws up back/forward
webView.loadDataWithBaseURL("file://error",
"<html><body>" + errorString + "</body></html>", "text/html", "utf-8",
failingUrl);
"<html><body>" + errorString + "</body></html>", "text/html", "utf-8", failingUrl);
String title = getResources().getString(R.string.app_name);
getActivity().getActionBar().setTitle(title);
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(title);
}
@Override
@ -1075,12 +1084,13 @@ public class KiwixMobileFragment extends Fragment {
title = webView.getTitle();
}
if (getActivity().getActionBar().getTabCount() < 2) {
getActivity().getActionBar().setTitle(title);
if (((ActionBarActivity) getActivity()).getSupportActionBar().getTabCount() < 2) {
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(title);
}
if (getActivity().getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) {
getActivity().getActionBar().getSelectedTab().setText(title);
if (((ActionBarActivity) getActivity()).getSupportActionBar().getNavigationMode()
== ActionBar.NAVIGATION_MODE_TABS) {
((ActionBarActivity) getActivity()).getSupportActionBar().getSelectedTab().setText(title);
}
// Workaround for #643

View File

@ -1,130 +0,0 @@
/*
* Copyright 2013 Rashiq Ahmad <rashiq.z@gmail.com>
*
* 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 3 of the License, or
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.kiwix.kiwixmobile;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceFragment;
import java.util.Locale;
public class KiwixSettings extends Activity {
public static final int RESULT_RESTART = 1236;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment()).commit();
new LanguageUtils(this).changeFont(getLayoutInflater());
}
public class PrefsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
prepareListPreferenceForAutoSummary("pref_zoom");
setUpLanguageChooser("pref_language_chooser");
setAppVersionNumber();
}
private void prepareListPreferenceForAutoSummary(String preferenceId) {
ListPreference prefList = (ListPreference) findPreference(preferenceId);
prefList.setDefaultValue(prefList.getEntryValues()[0]);
String summary = prefList.getValue();
if (summary == null) {
prefList.setValue((String) prefList.getEntryValues()[0]);
summary = prefList.getValue();
}
prefList.setSummary(prefList.getEntries()[prefList.findIndexOfValue(summary)]);
prefList.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference instanceof ListPreference) {
preference.setSummary(((ListPreference) preference)
.getEntries()[((ListPreference) preference)
.findIndexOfValue(newValue.toString())]);
}
return true;
}
});
}
private void setUpLanguageChooser(String preferenceId) {
ListPreference languageList = (ListPreference) findPreference(preferenceId);
LanguageUtils languageUtils = new LanguageUtils(getActivity());
languageList.setTitle(Locale.getDefault().getDisplayLanguage());
languageList.setEntries(languageUtils.getValues().toArray(new String[0]));
languageList.setEntryValues(languageUtils.getKeys().toArray(new String[0]));
languageList.setDefaultValue(Locale.getDefault().toString());
languageList.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (!newValue.equals(Locale.getDefault().toString())) {
LanguageUtils.handleLocaleChange(getActivity(), newValue.toString());
// Request a restart when the user returns to the Activity, that called this Activity
setResult(RESULT_RESTART);
finish();
startActivity(new Intent(getActivity(), KiwixSettings.class));
}
return true;
}
});
}
private void setAppVersionNumber() {
String version;
try {
version = getPackageManager().getPackageInfo("org.kiwix.kiwixmobile", 0).versionName;
} catch (NameNotFoundException e) {
return;
}
EditTextPreference versionPref = (EditTextPreference) findPreference("pref_version");
versionPref.setSummary(version);
}
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright 2013 Rashiq Ahmad <rashiq.z@gmail.com>
*
* 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 3 of the License, or
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.kiwix.kiwixmobile;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
import java.util.Locale;
public class KiwixSettingsActivity extends PreferenceActivity {
public static final int RESULT_RESTART = 1236;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
prepareListPreferenceForAutoSummary("pref_zoom");
setUpLanguageChooser("pref_language_chooser");
setAppVersionNumber();
new LanguageUtils(this).changeFont(getLayoutInflater());
}
private void prepareListPreferenceForAutoSummary(String preferenceId) {
ListPreference prefList = (ListPreference) findPreference(preferenceId);
prefList.setDefaultValue(prefList.getEntryValues()[0]);
String summary = prefList.getValue();
if (summary == null) {
prefList.setValue((String) prefList.getEntryValues()[0]);
summary = prefList.getValue();
}
prefList.setSummary(prefList.getEntries()[prefList.findIndexOfValue(summary)]);
prefList.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference instanceof ListPreference) {
preference.setSummary(((ListPreference) preference)
.getEntries()[((ListPreference) preference)
.findIndexOfValue(newValue.toString())]);
}
return true;
}
});
}
private void setUpLanguageChooser(String preferenceId) {
ListPreference languageList = (ListPreference) findPreference(preferenceId);
LanguageUtils languageUtils = new LanguageUtils(KiwixSettingsActivity.this);
languageList.setTitle(Locale.getDefault().getDisplayLanguage());
languageList.setEntries(languageUtils.getValues().toArray(new String[0]));
languageList.setEntryValues(languageUtils.getKeys().toArray(new String[0]));
languageList.setDefaultValue(Locale.getDefault().toString());
languageList.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (!newValue.equals(Locale.getDefault().toString())) {
LanguageUtils.handleLocaleChange(KiwixSettingsActivity.this, newValue.toString());
// Request a restart when the user returns to the Activity, that called this Activity
setResult(RESULT_RESTART);
finish();
startActivity(new Intent(KiwixSettingsActivity.this, KiwixSettingsActivity.class));
}
return true;
}
});
}
private void setAppVersionNumber() {
String version;
try {
version = getPackageManager().getPackageInfo("org.kiwix.kiwixmobile", 0).versionName;
} catch (NameNotFoundException e) {
return;
}
EditTextPreference versionPref = (EditTextPreference) findPreference("pref_version");
versionPref.setSummary(version);
}
}

View File

@ -21,11 +21,16 @@ package org.kiwix.kiwixmobile;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.webkit.WebView;
import android.widget.ZoomButtonsController;
/*
* Custom version of link{@android.webkit.WebView}
* to get scroll positions for implimenting the Back to top
import java.lang.reflect.Method;
import static org.kiwix.kiwixmobile.BackwardsCompatibilityTools.newApi;
/**
* A custom WebView to get scroll positions for implimenting the Back-To-Top Button
*/
public class KiwixWebView extends WebView {
@ -33,6 +38,10 @@ public class KiwixWebView extends WebView {
private OnLongClickListener mOnLongClickListener;
private ZoomButtonsController zoomControll = null;
private boolean mDisableZoomControlls;
public KiwixWebView(Context context) {
super(context);
@ -63,12 +72,45 @@ public class KiwixWebView extends WebView {
int windowHeight = getMeasuredHeight();
int pages = getContentHeight() / windowHeight;
int page = t / windowHeight;
//alert the listeners
// Alert the listener
if (mChangeListener != null) {
mChangeListener.onPageChanged(page, pages);
}
}
public void disableZoomControlls(boolean disable) {
mDisableZoomControlls = disable;
if (newApi()) {
getSettings().setBuiltInZoomControls(true);
getSettings().setDisplayZoomControls(disable);
} else {
getZoomControlls();
}
}
// Use reflection to hide the zoom controlls
private void getZoomControlls() {
try {
Class webview = Class.forName("android.webkit.WebView");
Method method = webview.getMethod("getZoomButtonsController");
zoomControll = (ZoomButtonsController) method.invoke(this, null);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
if (zoomControll != null) {
zoomControll.setVisible(mDisableZoomControlls);
}
return true;
}
public void setOnPageChangedListener(OnPageChangeListener listener) {
mChangeListener = listener;
}

View File

@ -22,6 +22,7 @@ package org.kiwix.kiwixmobile;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Handler;
import android.preference.PreferenceManager;
@ -32,6 +33,7 @@ import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -160,11 +162,13 @@ public class LanguageUtils {
layoutInflater.setFactory(new LayoutInflaterFactory(mContext, layoutInflater));
} catch (NoSuchFieldException e) {
Log.e("kiwix", "could not access private field of the LayoutInflater");
} catch (IllegalArgumentException e) {
Log.e("kiwix", "could not access private field of the LayoutInflater");
} catch (IllegalAccessException e) {
Log.e("kiwix", "could not access private field of the LayoutInflater");
}
}
@ -226,17 +230,17 @@ public class LanguageUtils {
Log.d("kiwix", "Applying custom font");
// Reduce the text size
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textView.getTextSize() - 3f);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textView.getTextSize() - 2f);
}
});
return view;
} catch (InflateException e) {
Log.e("kiwix", "Could not apply the custom font");
Log.e("kiwix", "Could not apply the custom font to " + name + " " + e.getMessage());
} catch (ClassNotFoundException e) {
Log.e("kiwix", "Could not apply the custom font");
Log.e("kiwix", "Could not apply the custom font to " + name + " " + e.getMessage());
}
}
@ -245,12 +249,13 @@ public class LanguageUtils {
// This method will determine which font will be applied to the not-supported-locale.
// You can define exceptions to the default DejaVu font in the 'exceptions' Hashmap:
private String getTypeface() {
// Define the exceptions to the rule. The font has to be placed in the assets folder.
// Key: the language code; Value: the name of the font.
HashMap<String, String> exceptions = new HashMap<String, String>();
exceptions.put("my", "Parabaik.ttf");
exceptions.put("my", "fonts/Parabaik.ttf");
// Check, if an exception applies to our current locale
if (exceptions.containsKey(Locale.getDefault().getLanguage())) {
@ -258,7 +263,7 @@ public class LanguageUtils {
}
// Return the default font
return "DejaVuSansCondensed.ttf";
return "fonts/DejaVuSansCondensed.ttf";
}
}

View File

@ -19,11 +19,6 @@
package org.kiwix.kiwixmobile;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
@ -32,223 +27,238 @@ import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
public class ZimContentProvider extends ContentProvider {
public static final Uri CONTENT_URI = Uri.parse("content://org.kiwix.zim/");
public static final Uri UI_URI = Uri.parse("content://org.kiwix.ui/");
private static String zimFileName;
private static JNIKiwix jniKiwix;
public synchronized static String setZimFile(String fileName) {
if (!jniKiwix.loadZIM(fileName)) {
Log.e("kiwix", "Unable to open the file " + fileName);
zimFileName = null;
} else {
zimFileName = fileName;
}
return zimFileName;
}
public static final Uri CONTENT_URI = Uri.parse("content://org.kiwix.zim/");
public static final Uri UI_URI = Uri.parse("content://org.kiwix.ui/");
private static String zimFileName;
private static JNIKiwix jniKiwix;
public synchronized static String setZimFile(String fileName) {
if (!jniKiwix.loadZIM(fileName)) {
Log.e("kiwix", "Unable to open the file " + fileName);
zimFileName = null;
} else {
zimFileName = fileName;
}
return zimFileName;
}
public static String getZimFile() {
return zimFileName;
}
public static String getZimFileTitle() {
if (jniKiwix == null || zimFileName == null) {
return null;
} else {
JNIKiwixString title = new JNIKiwixString();
if (jniKiwix.getTitle(title)) {
return title.value;
} else {
return null;
}
}
}
public static String getZimFile() {
return zimFileName;
}
public static String getZimFileTitle() {
if (jniKiwix==null || zimFileName==null)
return null;
else {
JNIKiwixString title = new JNIKiwixString();
if (jniKiwix.getTitle(title)) {
return title.value;
}
else return null;
}
}
public static String getMainPage() {
if (jniKiwix==null || zimFileName==null)
return null;
else {
return jniKiwix.getMainPage();
}
}
if (jniKiwix == null || zimFileName == null) {
return null;
} else {
return jniKiwix.getMainPage();
}
}
public static String getId() {
if (jniKiwix==null || zimFileName==null)
return null;
else {
return jniKiwix.getId();
}
}
public static boolean searchSuggestions(String prefix, int count) {
if (jniKiwix==null || zimFileName==null)
return false;
else {
return jniKiwix.searchSuggestions(prefix, count);
}
}
public static String getNextSuggestion() {
if (jniKiwix==null || zimFileName==null)
return null;
else {
JNIKiwixString title=new JNIKiwixString();
if (jniKiwix.getNextSuggestion(title)) {
return title.value;
}
else {
return null;
}
}
}
public static String getPageUrlFromTitle(String title) {
if (jniKiwix==null || zimFileName==null)
return null;
else {
JNIKiwixString url=new JNIKiwixString();
if (jniKiwix.getPageUrlFromTitle(title, url)) {
return url.value;
} else {
return null;
}
}
}
public static String getRandomArticleUrl() {
if (jniKiwix==null || zimFileName==null)
return null;
else {
JNIKiwixString url=new JNIKiwixString();
if (jniKiwix.getRandomPage(url)) {
return url.value;
} else {
return null;
}
}
}
@Override
public boolean onCreate() {
jniKiwix = new JNIKiwix();
return (true);
}
if (jniKiwix == null || zimFileName == null) {
return null;
} else {
return jniKiwix.getId();
}
}
@Override
public String getType(Uri uri) {
Log.w("kiwix", "ZimContentProvider.getType() (not implemented) called");
return null;
}
public static boolean searchSuggestions(String prefix, int count) {
if (jniKiwix == null || zimFileName == null) {
return false;
} else {
return jniKiwix.searchSuggestions(prefix, count);
}
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
ParcelFileDescriptor[] pipe = null;
public static String getNextSuggestion() {
if (jniKiwix == null || zimFileName == null) {
return null;
} else {
JNIKiwixString title = new JNIKiwixString();
if (jniKiwix.getNextSuggestion(title)) {
return title.value;
} else {
return null;
}
}
}
try {
pipe = ParcelFileDescriptor.createPipe();
new TransferThread(jniKiwix, uri, new AutoCloseOutputStream(
pipe[1])).start();
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
throw new FileNotFoundException("Could not open pipe for: "
+ uri.toString());
}
public static String getPageUrlFromTitle(String title) {
if (jniKiwix == null || zimFileName == null) {
return null;
} else {
JNIKiwixString url = new JNIKiwixString();
if (jniKiwix.getPageUrlFromTitle(title, url)) {
return url.value;
} else {
return null;
}
}
}
return (pipe[0]);
}
public static String getRandomArticleUrl() {
if (jniKiwix == null || zimFileName == null) {
return null;
} else {
JNIKiwixString url = new JNIKiwixString();
if (jniKiwix.getRandomPage(url)) {
return url.value;
} else {
return null;
}
}
}
@Override
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
throw new RuntimeException("Operation not supported");
}
@Override
public boolean onCreate() {
jniKiwix = new JNIKiwix();
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
throw new RuntimeException("Operation not supported");
}
return (true);
}
@Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
@Override
public String getType(Uri uri) {
Log.w("kiwix", "ZimContentProvider.getType() (not implemented) called");
return null;
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
ParcelFileDescriptor[] pipe = null;
static class TransferThread extends Thread {
try {
pipe = ParcelFileDescriptor.createPipe();
new TransferThread(jniKiwix, uri, new AutoCloseOutputStream(
pipe[1])).start();
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
throw new FileNotFoundException("Could not open pipe for: "
+ uri.toString());
}
Uri articleUri;
String articleZimUrl;
OutputStream out;
JNIKiwix jniKiwix;
return (pipe[0]);
}
TransferThread(JNIKiwix jniKiwix, Uri articleUri, OutputStream out) throws IOException {
this.articleUri = articleUri;
this.jniKiwix = jniKiwix;
Log.d("kiwix",
"Retrieving :"
+ articleUri.toString());
String t = articleUri.toString();
int pos = articleUri.toString().indexOf(CONTENT_URI.toString());
if (pos != -1)
t = articleUri.toString().substring(
CONTENT_URI.toString().length());
// Remove fragment (#...) as not supported by zimlib
pos = t.indexOf("#");
if (pos != -1) {
t = t.substring(0, pos);
}
this.out = out;
this.articleZimUrl = t;
}
@Override
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
throw new RuntimeException("Operation not supported");
}
@Override
public void run() {
byte[] buf = new byte[1024];
int len;
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
throw new RuntimeException("Operation not supported");
}
try {
JNIKiwixString mime = new JNIKiwixString();
JNIKiwixInt size = new JNIKiwixInt();
byte[] data = jniKiwix.getContent(articleZimUrl, mime, size);
// Log.d("kiwix","articleDataByteArray:"+articleDataByteArray.toString());
// ByteArrayInputStream articleDataInputStream = new
// ByteArrayInputStream(articleDataByteArray.toByteArray());
// Log.d("kiwix","article data loaded from zime file");
@Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
//ByteArrayInputStream articleDataInputStream = new ByteArrayInputStream(
// articleDataByteArray.toByteArray());
ByteArrayInputStream articleDataInputStream = new ByteArrayInputStream(data);
while ((len = articleDataInputStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
articleDataInputStream.close();
out.flush();
static class TransferThread extends Thread {
Log.d("kiwix", "reading " + articleZimUrl
+ "(mime "+mime.value+", size: "+size.value+") finished.");
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception reading article "
+ articleZimUrl + " from zim file", e);
} catch (NullPointerException e) {
Log.e(getClass().getSimpleName(), "Exception reading article "
+ articleZimUrl + " from zim file", e);
Uri articleUri;
} finally {
try {
out.close();
} catch (IOException e) {
}
String articleZimUrl;
}
}
}
OutputStream out;
JNIKiwix jniKiwix;
TransferThread(JNIKiwix jniKiwix, Uri articleUri, OutputStream out) throws IOException {
this.articleUri = articleUri;
this.jniKiwix = jniKiwix;
Log.d("kiwix",
"Retrieving :"
+ articleUri.toString());
String t = articleUri.toString();
int pos = articleUri.toString().indexOf(CONTENT_URI.toString());
if (pos != -1) {
t = articleUri.toString().substring(
CONTENT_URI.toString().length());
}
// Remove fragment (#...) as not supported by zimlib
pos = t.indexOf("#");
if (pos != -1) {
t = t.substring(0, pos);
}
this.out = out;
this.articleZimUrl = t;
}
@Override
public void run() {
byte[] buf = new byte[1024];
int len;
try {
JNIKiwixString mime = new JNIKiwixString();
JNIKiwixInt size = new JNIKiwixInt();
byte[] data = jniKiwix.getContent(articleZimUrl, mime, size);
// Log.d("kiwix","articleDataByteArray:"+articleDataByteArray.toString());
// ByteArrayInputStream articleDataInputStream = new
// ByteArrayInputStream(articleDataByteArray.toByteArray());
// Log.d("kiwix","article data loaded from zime file");
//ByteArrayInputStream articleDataInputStream = new ByteArrayInputStream(
// articleDataByteArray.toByteArray());
ByteArrayInputStream articleDataInputStream = new ByteArrayInputStream(data);
while ((len = articleDataInputStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
articleDataInputStream.close();
out.flush();
Log.d("kiwix", "reading " + articleZimUrl
+ "(mime " + mime.value + ", size: " + size.value + ") finished.");
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception reading article "
+ articleZimUrl + " from zim file", e);
} catch (NullPointerException e) {
Log.e(getClass().getSimpleName(), "Exception reading article "
+ articleZimUrl + " from zim file", e);
} finally {
try {
out.close();
} catch (IOException e) {
}
}
}
}
}

View File

@ -19,6 +19,7 @@
package org.kiwix.kiwixmobile;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
@ -27,17 +28,18 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
@ -45,12 +47,13 @@ import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ZimFileSelectActivity extends FragmentActivity
public class ZimFileSelectActivity extends ActionBarActivity
implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener {
private static final int LOADER_ID = 0x02;
@ -80,11 +83,12 @@ public class ZimFileSelectActivity extends FragmentActivity
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mProgressBarMessage = (TextView) findViewById(R.id.progressbar_message);
mZimFileList = (ListView) findViewById(R.id.zimfilelist);
mFiles = new ArrayList<DataModel>();
mZimFileList.setOnItemClickListener(this);
mProgressBar.setVisibility(View.VISIBLE);
// mZimFileList.setAlpha(0.4f);
mFiles = new ArrayList<DataModel>();
setAlpha(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
startQuery();
@ -93,8 +97,10 @@ public class ZimFileSelectActivity extends FragmentActivity
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
Uri uri = MediaStore.Files.getContentUri("external");
String[] projection = {
@ -137,7 +143,7 @@ public class ZimFileSelectActivity extends FragmentActivity
if (mProgressBarMessage.getVisibility() == View.GONE) {
mProgressBar.setVisibility(View.GONE);
// mZimFileList.setAlpha(1f);
setAlpha(false);
}
mCursorAdapter.notifyDataSetChanged();
@ -241,8 +247,6 @@ public class ZimFileSelectActivity extends FragmentActivity
// Flags for the Adapter
Adapter.NO_SELECTION);
mZimFileList.setOnItemClickListener(this);
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
}
@ -290,6 +294,21 @@ public class ZimFileSelectActivity extends FragmentActivity
}
}
// Make the View transparent or opaque
private void setAlpha(boolean transparent) {
float viewTransparency = transparent ? 0.4F : 1F;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mZimFileList.setAlpha(viewTransparency);
} else {
AlphaAnimation alpha = new AlphaAnimation(viewTransparency, viewTransparency);
alpha.setDuration(0);
alpha.setFillAfter(true);
mZimFileList.startAnimation(alpha);
}
}
// The Adapter for the ListView for when the ListView is populated with the rescanned files
private class RescanDataAdapter extends ArrayAdapter<DataModel> {
@ -336,7 +355,7 @@ public class ZimFileSelectActivity extends FragmentActivity
mProgressBarMessage.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
// mZimFileList.setAlpha(0.4f);
setAlpha(true);
super.onPreExecute();
}
@ -356,12 +375,11 @@ public class ZimFileSelectActivity extends FragmentActivity
mProgressBarMessage.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
// mZimFileList.setAlpha(1f);
setAlpha(false);
new FileWriter(ZimFileSelectActivity.this).saveArray(mFiles);
super.onPostExecute(result);
}
}
}