diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a18dfd556..913096658 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -15,10 +15,11 @@ - + + android:textColor="@android:color/white"/> diff --git a/res/layout/simple_list_item.xml b/res/layout/simple_list_item.xml new file mode 100644 index 000000000..050f1ab11 --- /dev/null +++ b/res/layout/simple_list_item.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/res/layout/webview_find.xml b/res/layout/webview_find.xml new file mode 100644 index 000000000..d5fd8643f --- /dev/null +++ b/res/layout/webview_find.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/res/menu/fileselector.xml b/res/menu/fileselector.xml index 14edd4f71..05a26b85d 100644 --- a/res/menu/fileselector.xml +++ b/res/menu/fileselector.xml @@ -1,11 +1,12 @@ - + + app:showAsAction="always"/> \ No newline at end of file diff --git a/res/menu/main.xml b/res/menu/main.xml index eb1cfad0e..a125bacad 100644 --- a/res/menu/main.xml +++ b/res/menu/main.xml @@ -1,81 +1,82 @@ - + + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> + app:showAsAction="never"/> + app:showAsAction="never"/> + app:showAsAction="never"/> + app:showAsAction="ifRoom"/> + app:showAsAction="never"/> diff --git a/res/menu/webview_menu.xml b/res/menu/webview_menu.xml new file mode 100644 index 000000000..0d9c3c7cb --- /dev/null +++ b/res/menu/webview_menu.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 0adbc1904..e30467886 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -54,4 +54,6 @@ Share via Language Choose a language + Delete Tab + Do you want to delete this tab? diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..0268643af --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':android' \ No newline at end of file diff --git a/src/org/kiwix/kiwixmobile/BackwardsCompatibilityTools.java b/src/org/kiwix/kiwixmobile/BackwardsCompatibilityTools.java new file mode 100644 index 000000000..50a7de603 --- /dev/null +++ b/src/org/kiwix/kiwixmobile/BackwardsCompatibilityTools.java @@ -0,0 +1,37 @@ +/* + * Copyright 2013 Rashiq Ahmad + * + * 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; + } + +} diff --git a/src/org/kiwix/kiwixmobile/CompatFindActionModeCallback.java b/src/org/kiwix/kiwixmobile/CompatFindActionModeCallback.java new file mode 100644 index 000000000..d9614ab74 --- /dev/null +++ b/src/org/kiwix/kiwixmobile/CompatFindActionModeCallback.java @@ -0,0 +1,209 @@ +/* + * Copyright 2013 Rashiq Ahmad + * + * 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. + } +} \ No newline at end of file diff --git a/src/org/kiwix/kiwixmobile/KiwixMobileActivity.java b/src/org/kiwix/kiwixmobile/KiwixMobileActivity.java index fd33fdd96..1991f64e3 100644 --- a/src/org/kiwix/kiwixmobile/KiwixMobileActivity.java +++ b/src/org/kiwix/kiwixmobile/KiwixMobileActivity.java @@ -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 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(); + 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 { diff --git a/src/org/kiwix/kiwixmobile/KiwixMobileFragment.java b/src/org/kiwix/kiwixmobile/KiwixMobileFragment.java index 338f088ac..5aed0febb 100644 --- a/src/org/kiwix/kiwixmobile/KiwixMobileFragment.java +++ b/src/org/kiwix/kiwixmobile/KiwixMobileFragment.java @@ -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", - "" + errorString + "", "text/html", "utf-8", - failingUrl); + "" + errorString + "", "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 diff --git a/src/org/kiwix/kiwixmobile/KiwixSettings.java b/src/org/kiwix/kiwixmobile/KiwixSettings.java deleted file mode 100644 index af851f572..000000000 --- a/src/org/kiwix/kiwixmobile/KiwixSettings.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2013 Rashiq Ahmad - * - * 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); - } - } -} \ No newline at end of file diff --git a/src/org/kiwix/kiwixmobile/KiwixSettingsActivity.java b/src/org/kiwix/kiwixmobile/KiwixSettingsActivity.java new file mode 100644 index 000000000..af4f55aa5 --- /dev/null +++ b/src/org/kiwix/kiwixmobile/KiwixSettingsActivity.java @@ -0,0 +1,117 @@ +/* + * Copyright 2013 Rashiq Ahmad + * + * 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); + } +} diff --git a/src/org/kiwix/kiwixmobile/KiwixWebView.java b/src/org/kiwix/kiwixmobile/KiwixWebView.java index 121f95527..539b16891 100644 --- a/src/org/kiwix/kiwixmobile/KiwixWebView.java +++ b/src/org/kiwix/kiwixmobile/KiwixWebView.java @@ -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; } diff --git a/src/org/kiwix/kiwixmobile/LanguageUtils.java b/src/org/kiwix/kiwixmobile/LanguageUtils.java index 941b1f2a9..e39d63b31 100644 --- a/src/org/kiwix/kiwixmobile/LanguageUtils.java +++ b/src/org/kiwix/kiwixmobile/LanguageUtils.java @@ -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 exceptions = new HashMap(); - 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"; } } diff --git a/src/org/kiwix/kiwixmobile/ZimContentProvider.java b/src/org/kiwix/kiwixmobile/ZimContentProvider.java index 028f15058..e6f930f67 100644 --- a/src/org/kiwix/kiwixmobile/ZimContentProvider.java +++ b/src/org/kiwix/kiwixmobile/ZimContentProvider.java @@ -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) { + + } + + } + } + } } \ No newline at end of file diff --git a/src/org/kiwix/kiwixmobile/ZimFileSelectActivity.java b/src/org/kiwix/kiwixmobile/ZimFileSelectActivity.java index 9426913b3..e549f7159 100644 --- a/src/org/kiwix/kiwixmobile/ZimFileSelectActivity.java +++ b/src/org/kiwix/kiwixmobile/ZimFileSelectActivity.java @@ -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, 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(); + + mZimFileList.setOnItemClickListener(this); mProgressBar.setVisibility(View.VISIBLE); - // mZimFileList.setAlpha(0.4f); - - mFiles = new ArrayList(); + 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 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 { @@ -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); } - } }