Initial commit
This commit is contained in:
commit
b5e775e520
35
AndroidManifest.xml
Normal file
35
AndroidManifest.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.annimon.win1251viewer"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.1" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="8"
|
||||
android:targetSdkVersion="17" />
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name" >
|
||||
|
||||
<activity android:name=".FileBrowserActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ViewTextActivity"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:mimeType ="text/*" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
17
ant.properties
Normal file
17
ant.properties
Normal file
@ -0,0 +1,17 @@
|
||||
# This file is used to override default values used by the Ant build system.
|
||||
#
|
||||
# This file must be checked into Version Control Systems, as it is
|
||||
# integral to the build system of your project.
|
||||
|
||||
# This file is only used by the Ant script.
|
||||
|
||||
# You can use this to override default values such as
|
||||
# 'source.dir' for the location of your java source folder and
|
||||
# 'out.dir' for the location of your output folder.
|
||||
|
||||
# You can also use it define how the release builds are signed by declaring
|
||||
# the following properties:
|
||||
# 'key.store' for the location of your keystore and
|
||||
# 'key.alias' for the name of the key to use.
|
||||
# The password will be asked during the build when you use the 'release' target.
|
||||
|
92
build.xml
Normal file
92
build.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="Win1251Viewer" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
20
proguard-project.txt
Normal file
20
proguard-project.txt
Normal file
@ -0,0 +1,20 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
40
proguard.cfg
Normal file
40
proguard.cfg
Normal file
@ -0,0 +1,40 @@
|
||||
-optimizationpasses 5
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-dontpreverify
|
||||
-verbose
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
11
project.properties
Normal file
11
project.properties
Normal file
@ -0,0 +1,11 @@
|
||||
# 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 use,
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-16
|
BIN
res/drawable-hdpi/ic_launcher.png
Normal file
BIN
res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
res/drawable-hdpi/icon_file.png
Normal file
BIN
res/drawable-hdpi/icon_file.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
res/drawable-hdpi/icon_folder.png
Normal file
BIN
res/drawable-hdpi/icon_folder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
res/drawable-ldpi/ic_launcher.png
Normal file
BIN
res/drawable-ldpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
res/drawable-mdpi/ic_launcher.png
Normal file
BIN
res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
23
res/layout/file_item.xml
Normal file
23
res/layout/file_item.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="2dp"
|
||||
android:paddingLeft="10dp" >
|
||||
|
||||
<ImageView android:id="@+id/file_item_icon"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:gravity="center"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<TextView android:id="@+id/file_item_name"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:paddingLeft="3dp"
|
||||
android:textSize="18sp" />
|
||||
|
||||
|
||||
</LinearLayout>
|
15
res/layout/main.xml
Normal file
15
res/layout/main.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<com.annimon.win1251viewer.ZoomingTextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars = "vertical"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
4
res/values/strings.xml
Normal file
4
res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Win1251Viewer</string>
|
||||
</resources>
|
45
src/com/annimon/text/CP1251Encoding.java
Normal file
45
src/com/annimon/text/CP1251Encoding.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* aNNiMON 2012
|
||||
* For more info visit http://annimon.com/
|
||||
*/
|
||||
package com.annimon.text;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class CP1251Encoding extends Encoding {
|
||||
|
||||
/** Таблица кодировки "windows-1251" */
|
||||
protected static char[] cp1251 = {
|
||||
'\u0410', '\u0411', '\u0412', '\u0413', '\u0414', '\u0415', '\u0416',
|
||||
'\u0417', '\u0418', '\u0419', '\u041A', '\u041B', '\u041C', '\u041D',
|
||||
'\u041E', '\u041F', '\u0420', '\u0421', '\u0422', '\u0423', '\u0424',
|
||||
'\u0425', '\u0426', '\u0427', '\u0428', '\u0429', '\u042A', '\u042B',
|
||||
'\u042C', '\u042D', '\u042E', '\u042F', '\u0430', '\u0431', '\u0432',
|
||||
'\u0433', '\u0434', '\u0435', '\u0436', '\u0437', '\u0438', '\u0439',
|
||||
'\u043A', '\u043B', '\u043C', '\u043D', '\u043E', '\u043F', '\u0440',
|
||||
'\u0441', '\u0442', '\u0443', '\u0444', '\u0445', '\u0446', '\u0447',
|
||||
'\u0448', '\u0449', '\u044A', '\u044B', '\u044C', '\u044D', '\u044E',
|
||||
'\u044F'
|
||||
};
|
||||
|
||||
public char decodeChar(byte b) {
|
||||
int ich = b & 0xff;
|
||||
if (ich == 0xb8) return 0x0451; // ё
|
||||
else if (ich == 0xa8) return 0x0401; // Ё
|
||||
else if (ich >= 0xc0) return cp1251[ich - 192];
|
||||
return (char) ich;
|
||||
}
|
||||
|
||||
public byte encodeChar(char ch) {
|
||||
if (ch > 0 && ch < 128) return (byte) ch;
|
||||
else if (ch == 0x401) return -88; // Ё
|
||||
else if (ch == 0x404) return -86; // Є
|
||||
else if (ch == 0x407) return -81; // Ї
|
||||
else if (ch == 0x451) return -72; // ё
|
||||
else if (ch == 0x454) return -70; // є
|
||||
else if (ch == 0x457) return -65; // ї
|
||||
return (byte) (ch + 176);
|
||||
}
|
||||
}
|
52
src/com/annimon/text/Encoding.java
Normal file
52
src/com/annimon/text/Encoding.java
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* aNNiMON 2012
|
||||
* For more info visit http://annimon.com/
|
||||
*/
|
||||
package com.annimon.text;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public abstract class Encoding {
|
||||
|
||||
protected String encoding;
|
||||
|
||||
public abstract char decodeChar(byte bt);
|
||||
|
||||
public abstract byte encodeChar(char ch);
|
||||
|
||||
/*
|
||||
* Кодировать строку s в кодировку enc
|
||||
*/
|
||||
public byte[] encodeString(String s, String enc) throws UnsupportedEncodingException {
|
||||
byte[] bs;
|
||||
try {
|
||||
bs = s.getBytes(enc);
|
||||
} catch (UnsupportedEncodingException x) {
|
||||
bs = new byte[s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
bs[i] = encodeChar(s.charAt(i));
|
||||
}
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Декодировать участок массива b длиной len со смещения off из кодировки enc
|
||||
*/
|
||||
public String decodeString(byte[] bs, int off, int len, String enc) throws UnsupportedEncodingException {
|
||||
try {
|
||||
String s = new String(bs, off, len, enc);
|
||||
return s;
|
||||
} catch (UnsupportedEncodingException x) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < len; i++) {
|
||||
sb.append( decodeChar(bs[off + i]) );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
151
src/com/annimon/win1251viewer/FileBrowser.java
Normal file
151
src/com/annimon/win1251viewer/FileBrowser.java
Normal file
@ -0,0 +1,151 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.os.Environment;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* File browser.
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class FileBrowser {
|
||||
|
||||
// Comparator for sorting files.
|
||||
private final FilesComparator filesComparator;
|
||||
// Filter for directories and files.
|
||||
private final FileFilter dirFilter, fileFilter;
|
||||
|
||||
private String startDir;
|
||||
private ListActivity activity;
|
||||
|
||||
private FileOpenEventListener fileOpenEventListener;
|
||||
|
||||
private List<String> item, path;
|
||||
private File currentDir;
|
||||
|
||||
public FileBrowser(ListActivity activity) {
|
||||
this(activity, Environment.getExternalStorageDirectory().getPath());
|
||||
}
|
||||
|
||||
public FileBrowser(ListActivity activity, String startDir) {
|
||||
this.activity = activity;
|
||||
this.startDir = startDir;
|
||||
|
||||
item = new ArrayList<String>();
|
||||
path = new ArrayList<String>();
|
||||
|
||||
filesComparator = new FilesComparator();
|
||||
dirFilter = new FileFilter() {
|
||||
// Filter only readable directories.
|
||||
public boolean accept(File file) {
|
||||
return (file.isDirectory() && !file.isHidden() && file.canRead());
|
||||
}
|
||||
};
|
||||
fileFilter = new FileFilter() {
|
||||
// Filter only readable files.
|
||||
public boolean accept(File file) {
|
||||
return (!file.isDirectory() && !file.isHidden() && file.canRead());
|
||||
}
|
||||
};
|
||||
// Begin scan files.
|
||||
scanDirectory(startDir);
|
||||
}
|
||||
|
||||
public void setFileOpenEventListener(FileOpenEventListener fileOpenEvent) {
|
||||
this.fileOpenEventListener = fileOpenEvent;
|
||||
}
|
||||
|
||||
public String getCurrentDir() {
|
||||
return currentDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
public void setCurrentDir(String path) {
|
||||
scanDirectory(path);
|
||||
}
|
||||
|
||||
public void itemSelected(int index) {
|
||||
File file = new File(path.get(index));
|
||||
|
||||
if (file.isDirectory()) {
|
||||
scanDirectory(path.get(index));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileOpenEventListener != null) {
|
||||
fileOpenEventListener.onFileOpen(file);
|
||||
}
|
||||
}
|
||||
|
||||
public void upDirectory() {
|
||||
if (currentDir.getPath().equals(startDir)) {
|
||||
activity.finish();
|
||||
} else {
|
||||
scanDirectory(currentDir.getParent());
|
||||
}
|
||||
}
|
||||
|
||||
public void rescanCurrentDirectory() {
|
||||
scanDirectory(currentDir.getPath());
|
||||
}
|
||||
|
||||
private void scanDirectory(String dirPath) {
|
||||
activity.setTitle(dirPath);
|
||||
|
||||
item.clear();
|
||||
path.clear();
|
||||
|
||||
File f = new File(dirPath);
|
||||
currentDir = f;
|
||||
|
||||
if (!dirPath.equals(startDir)) {
|
||||
item.add("../");
|
||||
path.add(f.getParent());
|
||||
}
|
||||
|
||||
addDirectories(f);
|
||||
addFiles(f);
|
||||
|
||||
FileListAdapter fileListAdapter = new FileListAdapter(activity, item);
|
||||
activity.setListAdapter(fileListAdapter);
|
||||
}
|
||||
|
||||
private void addDirectories(File file) {
|
||||
File[] directories = file.listFiles(dirFilter);
|
||||
sortFiles(directories);
|
||||
|
||||
for (int i = 0; i < directories.length; i++) {
|
||||
File f = directories[i];
|
||||
path.add(f.getPath());
|
||||
item.add(f.getName() + "/");
|
||||
}
|
||||
}
|
||||
|
||||
private void addFiles(File file) {
|
||||
File[] files = file.listFiles(fileFilter);
|
||||
sortFiles(files);
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File f = files[i];
|
||||
path.add(f.getPath());
|
||||
item.add(f.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void sortFiles(File[] files) {
|
||||
Arrays.sort(files, filesComparator);
|
||||
}
|
||||
|
||||
|
||||
private class FilesComparator implements Comparator<File> {
|
||||
|
||||
public int compare(File file1, File file2) {
|
||||
return file1.getName().compareToIgnoreCase(file2.getName());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
55
src/com/annimon/win1251viewer/FileBrowserActivity.java
Normal file
55
src/com/annimon/win1251viewer/FileBrowserActivity.java
Normal file
@ -0,0 +1,55 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class FileBrowserActivity extends ListActivity implements FileOpenEventListener {
|
||||
|
||||
private FileBrowser fileBrowser;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
fileBrowser = new FileBrowser(this);
|
||||
fileBrowser.setFileOpenEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putString("dir_path", fileBrowser.getCurrentDir());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
String dir = savedInstanceState.getString("dir_path");
|
||||
fileBrowser.setCurrentDir(dir);
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int index, long id) {
|
||||
fileBrowser.itemSelected(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
fileBrowser.upDirectory();
|
||||
}
|
||||
|
||||
public void onFileOpen(File openedFile) {
|
||||
Intent intent = new Intent(this, ViewTextActivity.class);
|
||||
intent.setData(Uri.fromFile(openedFile));
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
54
src/com/annimon/win1251viewer/FileListAdapter.java
Normal file
54
src/com/annimon/win1251viewer/FileListAdapter.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapter for listview [icon filename].
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class FileListAdapter extends BaseAdapter {
|
||||
|
||||
private LayoutInflater inflater;
|
||||
private List<String> objects;
|
||||
|
||||
public FileListAdapter(Context context, List<String> objects) {
|
||||
this.objects = objects;
|
||||
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return objects.size();
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return objects.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = convertView;
|
||||
if (view == null) {
|
||||
view = inflater.inflate(R.layout.file_item, parent, false);
|
||||
}
|
||||
|
||||
String item = (String) getItem(position);
|
||||
// Set icon by filename type.
|
||||
int iconId = item.endsWith("/") ? R.drawable.icon_folder : R.drawable.icon_file;
|
||||
((ImageView) view.findViewById(R.id.file_item_icon)).setImageResource(iconId);
|
||||
// Set filename.
|
||||
((TextView) view.findViewById(R.id.file_item_name)).setText(item);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
12
src/com/annimon/win1251viewer/FileOpenEventListener.java
Normal file
12
src/com/annimon/win1251viewer/FileOpenEventListener.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Listener for event, when user select a file.
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public interface FileOpenEventListener {
|
||||
|
||||
void onFileOpen(File openedFile);
|
||||
}
|
32
src/com/annimon/win1251viewer/StringEncoder.java
Normal file
32
src/com/annimon/win1251viewer/StringEncoder.java
Normal file
@ -0,0 +1,32 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
|
||||
|
||||
public class StringEncoder
|
||||
{
|
||||
protected static char[] cp1251 =
|
||||
{
|
||||
'\u0410', '\u0411', '\u0412', '\u0413', '\u0414', '\u0415', '\u0416',
|
||||
'\u0417', '\u0418', '\u0419', '\u041A', '\u041B', '\u041C', '\u041D',
|
||||
'\u041E', '\u041F', '\u0420', '\u0421', '\u0422', '\u0423', '\u0424',
|
||||
'\u0425', '\u0426', '\u0427', '\u0428', '\u0429', '\u042A', '\u042B',
|
||||
'\u042C', '\u042D', '\u042E', '\u042F', '\u0430', '\u0431', '\u0432',
|
||||
'\u0433', '\u0434', '\u0435', '\u0436', '\u0437', '\u0438', '\u0439',
|
||||
'\u043A', '\u043B', '\u043C', '\u043D', '\u043E', '\u043F', '\u0440',
|
||||
'\u0441', '\u0442', '\u0443', '\u0444', '\u0445', '\u0446', '\u0447',
|
||||
'\u0448', '\u0449', '\u044A', '\u044B', '\u044C', '\u044D', '\u044E',
|
||||
'\u044F'
|
||||
};
|
||||
|
||||
public static char decodeCharCP1251 (byte b)
|
||||
{
|
||||
int ich = b & 0xff;
|
||||
if (ich == 0xb8) // ё
|
||||
return 0x0451;
|
||||
else if (ich == 0xa8) // Ё
|
||||
return 0x0401;
|
||||
else if (ich >= 0xc0)
|
||||
return cp1251[ich-192];
|
||||
return (char)ich;
|
||||
}
|
||||
}
|
76
src/com/annimon/win1251viewer/ViewTextActivity.java
Normal file
76
src/com/annimon/win1251viewer/ViewTextActivity.java
Normal file
@ -0,0 +1,76 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
import android.app.*;
|
||||
import android.net.*;
|
||||
import android.os.*;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.view.*;
|
||||
import java.io.*;
|
||||
|
||||
public class ViewTextActivity extends Activity {
|
||||
|
||||
private ZoomingTextView textView;
|
||||
private boolean isUTF;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
isUTF = false;
|
||||
String text = getText(isUTF);
|
||||
textView = (ZoomingTextView) findViewById(R.id.textView);
|
||||
textView.setMovementMethod(new ScrollingMovementMethod());
|
||||
textView.setTextSize(18);
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(Menu.NONE, 0, Menu.NONE, "UTF-8");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
isUTF = !isUTF;
|
||||
textView.setText(getText(isUTF));
|
||||
item.setTitle(!isUTF ? "UTF-8" : "WIN-1251");
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getText(boolean utf) {
|
||||
String text;
|
||||
try {
|
||||
Uri fileUri = getIntent().getData();
|
||||
InputStream is = new FileInputStream(fileUri.getPath());
|
||||
text = getText(is, utf);
|
||||
is.close();
|
||||
} catch (Exception ex) {
|
||||
text = "No data";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private String getText(InputStream is, boolean utf) throws IOException {
|
||||
if (utf) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int oneByte;
|
||||
while ((oneByte = is.read()) != -1) {
|
||||
baos.write((byte) oneByte);
|
||||
}
|
||||
baos.flush();
|
||||
return new String(baos.toByteArray(), "UTF-8");
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int read;
|
||||
while ((read = is.read()) != -1) {
|
||||
sb.append(StringEncoder.decodeCharCP1251((byte) read));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
63
src/com/annimon/win1251viewer/ZoomingTextView.java
Normal file
63
src/com/annimon/win1251viewer/ZoomingTextView.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.annimon.win1251viewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public class ZoomingTextView extends TextView {
|
||||
|
||||
private static final int DEFAULT_TEXT_SIZE = 18;
|
||||
private static final int MINIMAL_TEXT_SIZE = 6, MAXIMAL_TEXT_SIZE = 50;
|
||||
private static final float MIN_SCALE = MINIMAL_TEXT_SIZE / (float) DEFAULT_TEXT_SIZE;
|
||||
private static final float MAX_SCALE = MAXIMAL_TEXT_SIZE / (float) DEFAULT_TEXT_SIZE;
|
||||
|
||||
private ScaleGestureDetector scaleDetector;
|
||||
private float scaleFactor;
|
||||
|
||||
public ZoomingTextView(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public ZoomingTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public ZoomingTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
|
||||
scaleFactor = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
scaleDetector.onTouchEvent(event);
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
|
||||
|
||||
@Override
|
||||
public boolean onScale(ScaleGestureDetector detector) {
|
||||
scaleFactor *= detector.getScaleFactor();
|
||||
scaleFactor = Math.max(MIN_SCALE, Math.min(scaleFactor, MAX_SCALE));
|
||||
|
||||
final int textSize = (int) (scaleFactor * DEFAULT_TEXT_SIZE);
|
||||
setTextSize(textSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user