Bug 650110 Update SUTAgent - adding in fencp, ffxcp, watcher code r=ctalbert
|
@ -72,7 +72,11 @@ endif
|
|||
DIRS += pgo
|
||||
|
||||
ifeq (Android,$(OS_TARGET))
|
||||
DIRS += mobile/sutagent/android
|
||||
DIRS += mobile/sutagent/android \
|
||||
mobile/sutagent/android/watcher \
|
||||
mobile/sutagent/android/ffxcp \
|
||||
mobile/sutagent/android/fencp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.fencp"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" android:sharedUserId="org.mozilla.fennec.sharedID">
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
|
||||
<activity android:label="@string/app_name" android:name="FenCP">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider android:name="FenCPFP"
|
||||
android:enabled="true"
|
||||
android:authorities="org.mozilla.fencp"
|
||||
android:exported="true">
|
||||
</provider>
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="6" />
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,175 @@
|
|||
package org.mozilla.fencp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
|
||||
public class DirCursor extends MatrixCursor {
|
||||
public static final String _ID = "_id";
|
||||
public static final String ISDIR = "isdir";
|
||||
public static final String FILENAME = "filename";
|
||||
public static final String LENGTH = "length";
|
||||
public static final String TIMESTAMP = "ts";
|
||||
public static final String WRITABLE = "writable";
|
||||
static final String[] DEFCOLUMNS = new String[] {
|
||||
_ID,
|
||||
ISDIR,
|
||||
FILENAME,
|
||||
LENGTH,
|
||||
TIMESTAMP,
|
||||
WRITABLE
|
||||
};
|
||||
private String dirPath = null;
|
||||
private String [] theColumns = null;
|
||||
|
||||
public DirCursor(String[] columnNames, String sPath) {
|
||||
super((columnNames == null ? DEFCOLUMNS : columnNames));
|
||||
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
|
||||
dirPath = sPath;
|
||||
doLoadCursor(dirPath);
|
||||
}
|
||||
|
||||
public DirCursor(String[] columnNames, int initialCapacity, String sPath) {
|
||||
super((columnNames == null ? DEFCOLUMNS : columnNames), initialCapacity);
|
||||
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
|
||||
dirPath = sPath;
|
||||
doLoadCursor(dirPath);
|
||||
}
|
||||
|
||||
private void doLoadCursor(String sDir) {
|
||||
File dir = new File(sDir);
|
||||
int nFiles = 0;
|
||||
int nCols = theColumns.length;
|
||||
int lcvFiles = 0;
|
||||
int nCIndex = 0;
|
||||
Object [] vals = new Object[nCols];
|
||||
|
||||
if (vals == null)
|
||||
return;
|
||||
|
||||
if (dir.isDirectory()) {
|
||||
try {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = -1;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 1;
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
try {
|
||||
vals[nCIndex] = dir.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
vals[nCIndex] = dir.getName();
|
||||
}
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(TIMESTAMP);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(WRITABLE);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = (dir.canWrite() ? 1 : 0);
|
||||
|
||||
addRow(vals);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
|
||||
File [] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
if ((nFiles = files.length) > 0) {
|
||||
for (lcvFiles = 0; lcvFiles < nFiles; lcvFiles++) {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = lcvFiles;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = (files[lcvFiles].isDirectory() ? 1 : 0);
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = files[lcvFiles].getName();
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = (files[lcvFiles].isDirectory() ? -1 : files[lcvFiles].length());
|
||||
|
||||
try {
|
||||
addRow(vals);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dir.isFile()) {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = -1;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = dir.getName();
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = dir.length();
|
||||
|
||||
nCIndex = getColumnIndex(TIMESTAMP);
|
||||
if (nCIndex > -1) {
|
||||
vals[nCIndex] = dir.lastModified();
|
||||
}
|
||||
|
||||
try {
|
||||
addRow(vals);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = -1;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = null;
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(TIMESTAMP);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
addRow(vals);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.mozilla.fencp;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class FenCP extends Activity {
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package org.mozilla.fencp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
public class FenCPFP extends ContentProvider {
|
||||
public static final String PROVIDER_NAME = "org.mozilla.fencp";
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/file");
|
||||
|
||||
public static final String _ID = "_id";
|
||||
public static final String ISDIR = "isdir";
|
||||
public static final String FILENAME = "filename";
|
||||
public static final String LENGTH = "length";
|
||||
public static final String CHUNK = "chunk";
|
||||
static String[] dircolumns = new String[] {
|
||||
_ID,
|
||||
ISDIR,
|
||||
FILENAME,
|
||||
LENGTH
|
||||
};
|
||||
|
||||
static String[] filecolumns = new String[] {
|
||||
_ID,
|
||||
CHUNK
|
||||
};
|
||||
|
||||
private static final int DIR = 1;
|
||||
private static final int FILE_NAME = 2;
|
||||
|
||||
private static final UriMatcher uriMatcher;
|
||||
static {
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
uriMatcher.addURI(PROVIDER_NAME, "dir", DIR);
|
||||
uriMatcher.addURI(PROVIDER_NAME, "file", FILE_NAME);
|
||||
}
|
||||
|
||||
public int PruneDir(String sTmpDir) {
|
||||
int nRet = 0;
|
||||
int nFiles = 0;
|
||||
String sSubDir = null;
|
||||
|
||||
File dir = new File(sTmpDir);
|
||||
|
||||
if (dir.isDirectory()) {
|
||||
File [] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
if ((nFiles = files.length) > 0) {
|
||||
for (int lcv = 0; lcv < nFiles; lcv++) {
|
||||
if (files[lcv].isDirectory()) {
|
||||
sSubDir = files[lcv].getAbsolutePath();
|
||||
nRet += PruneDir(sSubDir);
|
||||
}
|
||||
else {
|
||||
if (files[lcv].delete()) {
|
||||
nRet++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dir.delete()) {
|
||||
nRet++;
|
||||
}
|
||||
if ((nFiles + 1) > nRet) {
|
||||
nRet = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return(nRet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
int nFiles = 0;
|
||||
switch (uriMatcher.match(uri)) {
|
||||
case FILE_NAME:
|
||||
File f = new File(selection);
|
||||
if (f.delete())
|
||||
nFiles = 1;
|
||||
break;
|
||||
|
||||
case DIR:
|
||||
nFiles = PruneDir(selection);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri)
|
||||
{
|
||||
switch (uriMatcher.match(uri))
|
||||
{
|
||||
//---get directory---
|
||||
case DIR:
|
||||
return "vnd.android.cursor.dir/vnd.mozilla.dir ";
|
||||
//---get a particular file---
|
||||
case FILE_NAME:
|
||||
return "vnd.android.cursor.item/vnd.mozilla.file ";
|
||||
//---Unknown---
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported URI: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
Cursor retCursor = null;
|
||||
|
||||
switch(uriMatcher.match(uri)) {
|
||||
case DIR:
|
||||
retCursor = new DirCursor(projection, selection);
|
||||
break;
|
||||
|
||||
case FILE_NAME:
|
||||
retCursor = new FileCursor(projection, selection, selectionArgs);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (retCursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
int nRet = 0;
|
||||
FileOutputStream dstFile = null;
|
||||
|
||||
switch(uriMatcher.match(uri)) {
|
||||
case DIR:
|
||||
File dir = new File(selection);
|
||||
if (dir.mkdirs())
|
||||
nRet = 1;
|
||||
break;
|
||||
|
||||
case FILE_NAME:
|
||||
try {
|
||||
long lOffset = values.getAsLong("offset");
|
||||
byte [] buf = values.getAsByteArray(CHUNK);
|
||||
int nLength = values.getAsInteger(LENGTH);
|
||||
if ((buf != null) && (nLength > 0)) {
|
||||
File f = new File(selection);
|
||||
dstFile = new FileOutputStream(f, (lOffset == 0 ? false : true));
|
||||
dstFile.write(buf,0, nLength);
|
||||
dstFile.flush();
|
||||
dstFile.close();
|
||||
nRet = nLength;
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
} catch (IOException ioe) {
|
||||
try {
|
||||
dstFile.flush();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
try {
|
||||
dstFile.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package org.mozilla.fencp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import android.database.AbstractWindowedCursor;
|
||||
import android.database.CursorWindow;
|
||||
|
||||
public class FileCursor extends AbstractWindowedCursor {
|
||||
public static final String _ID = "_id";
|
||||
public static final String CHUNK = "chunk";
|
||||
public static final String LENGTH = "length";
|
||||
static final String[] DEFCOLUMNS = new String[] {
|
||||
_ID,
|
||||
CHUNK,
|
||||
LENGTH
|
||||
};
|
||||
private String filePath = null;
|
||||
private String [] theColumns = null;
|
||||
|
||||
private static final int BUFSIZE = 4096;
|
||||
private long lFileSize = 0;
|
||||
private int nCount = 0;
|
||||
private File theFile = null;
|
||||
private byte [] theBuffer = null;
|
||||
private long lOffset = 0;
|
||||
private long lLength = -1;
|
||||
|
||||
public FileCursor(String[] columnNames, String sFilePath, String [] selectionArgs) {
|
||||
super();
|
||||
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
|
||||
filePath = sFilePath;
|
||||
nCount = -1;
|
||||
|
||||
if ((selectionArgs != null) && (selectionArgs.length > 0)) {
|
||||
lOffset = Long.parseLong(selectionArgs[0]);
|
||||
lLength = Long.parseLong(selectionArgs[1]);
|
||||
}
|
||||
|
||||
if (filePath.length() > 0) {
|
||||
theFile = new File(filePath);
|
||||
if (theFile.exists() && theFile.canRead()) {
|
||||
lFileSize = theFile.length();
|
||||
|
||||
// lLength == -1 return everything between lOffset and eof
|
||||
// lLength == 0 return file length
|
||||
// lLength > 0 return lLength bytes
|
||||
if (lLength == -1) {
|
||||
lFileSize = lFileSize - lOffset;
|
||||
} else if (lLength == 0) {
|
||||
// just return the file length
|
||||
} else {
|
||||
lFileSize = ((lLength <= (lFileSize - lOffset)) ? lLength : (lFileSize - lOffset));
|
||||
}
|
||||
|
||||
if (lLength != 0) {
|
||||
nCount = (int) (lFileSize / BUFSIZE);
|
||||
if ((lFileSize % BUFSIZE) > 0)
|
||||
nCount++;
|
||||
} else {
|
||||
nCount = 1;
|
||||
}
|
||||
|
||||
mRowIdColumnIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getColumnName (int columnIndex) {
|
||||
return theColumns[columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getColumnNames() {
|
||||
return theColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return nCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(int oldPosition, int newPosition) {
|
||||
boolean bRet = true;
|
||||
|
||||
// get rid of old data
|
||||
mWindow.clear();
|
||||
bRet = mWindow.setNumColumns(theColumns.length);
|
||||
fillWindow(newPosition, mWindow);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillWindow (int pos, CursorWindow window) {
|
||||
int nNumRows = window.getNumRows();
|
||||
int nCIndex = 0;
|
||||
window.setStartPosition(0);
|
||||
|
||||
if (pos > -1) {
|
||||
if (nNumRows == 0) {
|
||||
window.allocRow();
|
||||
nNumRows = window.getNumRows();
|
||||
}
|
||||
|
||||
if (nNumRows == 1) {
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1) {
|
||||
window.putLong(lFileSize, 0, nCIndex);
|
||||
}
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1) {
|
||||
window.putLong((long)pos, 0, nCIndex);
|
||||
}
|
||||
nCIndex = getColumnIndex(CHUNK);
|
||||
if (nCIndex > -1) {
|
||||
if (lLength != 0) {
|
||||
byte[] value = getABlob (pos, 1);
|
||||
window.putBlob(value, 0, nCIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
window.setStartPosition(pos);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public byte[] getABlob (int row, int column) {
|
||||
int nRead = 0;
|
||||
int nOffset = 0;
|
||||
int nBufSize = 0;
|
||||
|
||||
if ((column == 1) && (theFile != null)) {
|
||||
try {
|
||||
FileInputStream fin = new FileInputStream(theFile);
|
||||
nOffset = row * BUFSIZE;
|
||||
if (row < (nCount - 1)) {
|
||||
nBufSize = BUFSIZE;
|
||||
} else {
|
||||
nBufSize = (int) (lFileSize - nOffset);
|
||||
}
|
||||
theBuffer = new byte[nBufSize];
|
||||
|
||||
if (theBuffer != null) {
|
||||
if (fin.skip(nOffset + lOffset) == (nOffset + lOffset)) {
|
||||
if ((nRead = fin.read(theBuffer, 0, nBufSize)) != -1) {
|
||||
if (nRead != nBufSize) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fin.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return theBuffer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Android sutagent for testing.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Clint Talbert <ctalbert@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = FenCP
|
||||
|
||||
JAVAFILES = \
|
||||
DirCursor.java \
|
||||
FenCP.java \
|
||||
FenCPFP.java \
|
||||
FileCursor.java \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
res/drawable-hdpi/icon.png \
|
||||
res/drawable-ldpi/icon.png \
|
||||
res/drawable-mdpi/icon.png \
|
||||
res/layout/main.xml \
|
||||
res/values/strings.xml \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
FenCP.apk \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE_DIRS += res classes network-libs
|
||||
|
||||
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# include Android specific java flags - using these instead of what's in rules.mk
|
||||
include $(topsrcdir)/config/android-common.mk
|
||||
|
||||
tools:: FenCP.apk
|
||||
|
||||
classes.dex: $(JAVAFILES)
|
||||
$(NSINSTALL) -D classes
|
||||
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
|
||||
$(DX) --dex --output=$@ classes
|
||||
|
||||
FenCP.ap_: $(srcdir)/AndroidManifest.xml
|
||||
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
|
||||
|
||||
FenCP-unsigned-unaligned.apk: FenCP.ap_ classes.dex
|
||||
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FenCP.ap_ -f classes.dex
|
||||
|
||||
FenCP-unaligned.apk: FenCP-unsigned-unaligned.apk
|
||||
cp FenCP-unsigned-unaligned.apk $@
|
||||
ifdef JARSIGNER
|
||||
$(JARSIGNER) $@
|
||||
endif
|
||||
|
||||
FenCP.apk: FenCP-unaligned.apk
|
||||
$(ZIPALIGN) -f -v 4 FenCP-unaligned.apk $@
|
||||
|
||||
export::
|
||||
$(NSINSTALL) -D res
|
||||
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/fencp/res && tar -xf -)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package org.mozilla.fencp;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int icon=0x7f020000;
|
||||
}
|
||||
public static final class layout {
|
||||
public static final int main=0x7f030000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int app_name=0x7f040001;
|
||||
public static final int hello=0x7f040000;
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-6
|
После Ширина: | Высота: | Размер: 4.0 KiB |
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="hello">Hello World, FennecCP!</string>
|
||||
<string name="app_name">FennecCP</string>
|
||||
</resources>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.ffxcp"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" android:sharedUserId="org.mozilla.firefox.sharedID">
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
|
||||
<activity android:label="@string/app_name" android:name="ffxcp">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider android:name="FfxCPFP"
|
||||
android:enabled="true"
|
||||
android:authorities="org.mozilla.ffxcp"
|
||||
android:exported="true">
|
||||
</provider>
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="6" />
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,175 @@
|
|||
package org.mozilla.ffxcp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
|
||||
public class DirCursor extends MatrixCursor {
|
||||
public static final String _ID = "_id";
|
||||
public static final String ISDIR = "isdir";
|
||||
public static final String FILENAME = "filename";
|
||||
public static final String LENGTH = "length";
|
||||
public static final String TIMESTAMP = "ts";
|
||||
public static final String WRITABLE = "writable";
|
||||
static final String[] DEFCOLUMNS = new String[] {
|
||||
_ID,
|
||||
ISDIR,
|
||||
FILENAME,
|
||||
LENGTH,
|
||||
TIMESTAMP,
|
||||
WRITABLE
|
||||
};
|
||||
private String dirPath = null;
|
||||
private String [] theColumns = null;
|
||||
|
||||
public DirCursor(String[] columnNames, String sPath) {
|
||||
super((columnNames == null ? DEFCOLUMNS : columnNames));
|
||||
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
|
||||
dirPath = sPath;
|
||||
doLoadCursor(dirPath);
|
||||
}
|
||||
|
||||
public DirCursor(String[] columnNames, int initialCapacity, String sPath) {
|
||||
super((columnNames == null ? DEFCOLUMNS : columnNames), initialCapacity);
|
||||
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
|
||||
dirPath = sPath;
|
||||
doLoadCursor(dirPath);
|
||||
}
|
||||
|
||||
private void doLoadCursor(String sDir) {
|
||||
File dir = new File(sDir);
|
||||
int nFiles = 0;
|
||||
int nCols = theColumns.length;
|
||||
int lcvFiles = 0;
|
||||
int nCIndex = 0;
|
||||
Object [] vals = new Object[nCols];
|
||||
|
||||
if (vals == null)
|
||||
return;
|
||||
|
||||
if (dir.isDirectory()) {
|
||||
try {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = -1;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 1;
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
try {
|
||||
vals[nCIndex] = dir.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
vals[nCIndex] = dir.getName();
|
||||
}
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(TIMESTAMP);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(WRITABLE);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = (dir.canWrite() ? 1 : 0);
|
||||
|
||||
addRow(vals);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
|
||||
File [] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
if ((nFiles = files.length) > 0) {
|
||||
for (lcvFiles = 0; lcvFiles < nFiles; lcvFiles++) {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = lcvFiles;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = (files[lcvFiles].isDirectory() ? 1 : 0);
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = files[lcvFiles].getName();
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = (files[lcvFiles].isDirectory() ? -1 : files[lcvFiles].length());
|
||||
|
||||
try {
|
||||
addRow(vals);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dir.isFile()) {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = -1;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = dir.getName();
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = dir.length();
|
||||
|
||||
nCIndex = getColumnIndex(TIMESTAMP);
|
||||
if (nCIndex > -1) {
|
||||
vals[nCIndex] = dir.lastModified();
|
||||
}
|
||||
|
||||
try {
|
||||
addRow(vals);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = -1;
|
||||
|
||||
nCIndex = getColumnIndex(ISDIR);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(FILENAME);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = null;
|
||||
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
nCIndex = getColumnIndex(TIMESTAMP);
|
||||
if (nCIndex > -1)
|
||||
vals[nCIndex] = 0;
|
||||
|
||||
addRow(vals);
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
iae.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package org.mozilla.ffxcp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
public class FfxCPFP extends ContentProvider {
|
||||
public static final String PROVIDER_NAME = "org.mozilla.ffxcp";
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/file");
|
||||
|
||||
public static final String _ID = "_id";
|
||||
public static final String ISDIR = "isdir";
|
||||
public static final String FILENAME = "filename";
|
||||
public static final String LENGTH = "length";
|
||||
public static final String CHUNK = "chunk";
|
||||
static String[] dircolumns = new String[] {
|
||||
_ID,
|
||||
ISDIR,
|
||||
FILENAME,
|
||||
LENGTH
|
||||
};
|
||||
|
||||
static String[] filecolumns = new String[] {
|
||||
_ID,
|
||||
CHUNK
|
||||
};
|
||||
|
||||
private static final int DIR = 1;
|
||||
private static final int FILE_NAME = 2;
|
||||
|
||||
private static final UriMatcher uriMatcher;
|
||||
static {
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
uriMatcher.addURI(PROVIDER_NAME, "dir", DIR);
|
||||
uriMatcher.addURI(PROVIDER_NAME, "file", FILE_NAME);
|
||||
}
|
||||
|
||||
public int PruneDir(String sTmpDir) {
|
||||
int nRet = 0;
|
||||
int nFiles = 0;
|
||||
String sSubDir = null;
|
||||
|
||||
File dir = new File(sTmpDir);
|
||||
|
||||
if (dir.isDirectory()) {
|
||||
File [] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
if ((nFiles = files.length) > 0) {
|
||||
for (int lcv = 0; lcv < nFiles; lcv++) {
|
||||
if (files[lcv].isDirectory()) {
|
||||
sSubDir = files[lcv].getAbsolutePath();
|
||||
nRet += PruneDir(sSubDir);
|
||||
}
|
||||
else {
|
||||
if (files[lcv].delete()) {
|
||||
nRet++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dir.delete()) {
|
||||
nRet++;
|
||||
}
|
||||
if ((nFiles + 1) > nRet) {
|
||||
nRet = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return(nRet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
int nFiles = 0;
|
||||
switch (uriMatcher.match(uri)) {
|
||||
case FILE_NAME:
|
||||
File f = new File(selection);
|
||||
if (f.delete())
|
||||
nFiles = 1;
|
||||
break;
|
||||
|
||||
case DIR:
|
||||
nFiles = PruneDir(selection);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri)
|
||||
{
|
||||
switch (uriMatcher.match(uri))
|
||||
{
|
||||
//---get directory---
|
||||
case DIR:
|
||||
return "vnd.android.cursor.dir/vnd.mozilla.dir ";
|
||||
//---get a particular file---
|
||||
case FILE_NAME:
|
||||
return "vnd.android.cursor.item/vnd.mozilla.file ";
|
||||
//---Unknown---
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported URI: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
Cursor retCursor = null;
|
||||
|
||||
switch(uriMatcher.match(uri)) {
|
||||
case DIR:
|
||||
retCursor = new DirCursor(projection, selection);
|
||||
break;
|
||||
|
||||
case FILE_NAME:
|
||||
retCursor = new FileCursor(projection, selection, selectionArgs);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (retCursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
int nRet = 0;
|
||||
FileOutputStream dstFile = null;
|
||||
|
||||
switch(uriMatcher.match(uri)) {
|
||||
case DIR:
|
||||
File dir = new File(selection);
|
||||
if (dir.mkdirs())
|
||||
nRet = 1;
|
||||
break;
|
||||
|
||||
case FILE_NAME:
|
||||
try {
|
||||
long lOffset = values.getAsLong("offset");
|
||||
byte [] buf = values.getAsByteArray(CHUNK);
|
||||
int nLength = values.getAsInteger(LENGTH);
|
||||
if ((buf != null) && (nLength > 0)) {
|
||||
File f = new File(selection);
|
||||
dstFile = new FileOutputStream(f, (lOffset == 0 ? false : true));
|
||||
dstFile.write(buf,0, nLength);
|
||||
dstFile.flush();
|
||||
dstFile.close();
|
||||
nRet = nLength;
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
} catch (IOException ioe) {
|
||||
try {
|
||||
dstFile.flush();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
try {
|
||||
dstFile.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package org.mozilla.ffxcp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.database.AbstractWindowedCursor;
|
||||
import android.database.CursorWindow;
|
||||
|
||||
public class FileCursor extends AbstractWindowedCursor {
|
||||
public static final String _ID = "_id";
|
||||
public static final String CHUNK = "chunk";
|
||||
public static final String LENGTH = "length";
|
||||
static final String[] DEFCOLUMNS = new String[] {
|
||||
_ID,
|
||||
CHUNK,
|
||||
LENGTH
|
||||
};
|
||||
private String filePath = null;
|
||||
private String [] theColumns = null;
|
||||
|
||||
private static final int BUFSIZE = 4096;
|
||||
private long lFileSize = 0;
|
||||
private int nCount = 0;
|
||||
private File theFile = null;
|
||||
private byte [] theBuffer = null;
|
||||
private long lOffset = 0;
|
||||
private long lLength = -1;
|
||||
|
||||
public FileCursor(String[] columnNames, String sFilePath, String [] selectionArgs) {
|
||||
super();
|
||||
theColumns = (columnNames == null ? DEFCOLUMNS : columnNames);
|
||||
filePath = sFilePath;
|
||||
nCount = -1;
|
||||
|
||||
if ((selectionArgs != null) && (selectionArgs.length > 0)) {
|
||||
lOffset = Long.parseLong(selectionArgs[0]);
|
||||
lLength = Long.parseLong(selectionArgs[1]);
|
||||
}
|
||||
|
||||
if (filePath.length() > 0) {
|
||||
theFile = new File(filePath);
|
||||
if (theFile.exists() && theFile.canRead()) {
|
||||
lFileSize = theFile.length();
|
||||
|
||||
// lLength == -1 return everything between lOffset and eof
|
||||
// lLength == 0 return file length
|
||||
// lLength > 0 return lLength bytes
|
||||
if (lLength == -1) {
|
||||
lFileSize = lFileSize - lOffset;
|
||||
} else if (lLength == 0) {
|
||||
// just return the file length
|
||||
} else {
|
||||
lFileSize = ((lLength <= (lFileSize - lOffset)) ? lLength : (lFileSize - lOffset));
|
||||
}
|
||||
|
||||
if (lLength != 0) {
|
||||
nCount = (int) (lFileSize / BUFSIZE);
|
||||
if ((lFileSize % BUFSIZE) > 0)
|
||||
nCount++;
|
||||
} else {
|
||||
nCount = 1;
|
||||
}
|
||||
|
||||
mRowIdColumnIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getColumnName (int columnIndex) {
|
||||
return theColumns[columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getColumnNames() {
|
||||
return theColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return nCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(int oldPosition, int newPosition) {
|
||||
boolean bRet = true;
|
||||
|
||||
// get rid of old data
|
||||
mWindow.clear();
|
||||
bRet = mWindow.setNumColumns(theColumns.length);
|
||||
fillWindow(newPosition, mWindow);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillWindow (int pos, CursorWindow window) {
|
||||
int nNumRows = window.getNumRows();
|
||||
int nCIndex = 0;
|
||||
window.setStartPosition(0);
|
||||
|
||||
if (pos > -1) {
|
||||
if (nNumRows == 0) {
|
||||
window.allocRow();
|
||||
nNumRows = window.getNumRows();
|
||||
}
|
||||
|
||||
if (nNumRows == 1) {
|
||||
nCIndex = getColumnIndex(LENGTH);
|
||||
if (nCIndex > -1) {
|
||||
window.putLong(lFileSize, 0, nCIndex);
|
||||
}
|
||||
nCIndex = getColumnIndex(_ID);
|
||||
if (nCIndex > -1) {
|
||||
window.putLong((long)pos, 0, nCIndex);
|
||||
}
|
||||
nCIndex = getColumnIndex(CHUNK);
|
||||
if (nCIndex > -1) {
|
||||
if (lLength != 0) {
|
||||
byte[] value = getABlob (pos, 1);
|
||||
window.putBlob(value, 0, nCIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
window.setStartPosition(pos);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public byte[] getABlob (int row, int column) {
|
||||
int nRead = 0;
|
||||
int nOffset = 0;
|
||||
int nBufSize = 0;
|
||||
|
||||
if ((column == 1) && (theFile != null)) {
|
||||
try {
|
||||
FileInputStream fin = new FileInputStream(theFile);
|
||||
nOffset = row * BUFSIZE;
|
||||
if (row < (nCount - 1)) {
|
||||
nBufSize = BUFSIZE;
|
||||
} else {
|
||||
nBufSize = (int) (lFileSize - nOffset);
|
||||
}
|
||||
theBuffer = new byte[nBufSize];
|
||||
|
||||
if (theBuffer != null) {
|
||||
if (fin.skip(nOffset + lOffset) == (nOffset + lOffset)) {
|
||||
if ((nRead = fin.read(theBuffer, 0, nBufSize)) != -1) {
|
||||
if (nRead != nBufSize) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fin.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return theBuffer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Android sutagent for testing.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Clint Talbert <ctalbert@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = FfxCP
|
||||
|
||||
JAVAFILES = \
|
||||
DirCursor.java \
|
||||
ffxcp.java \
|
||||
FfxCPFP.java \
|
||||
FileCursor.java \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
res/drawable-hdpi/icon.png \
|
||||
res/drawable-ldpi/icon.png \
|
||||
res/drawable-mdpi/icon.png \
|
||||
res/layout/main.xml \
|
||||
res/values/strings.xml \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
FfxCP.apk \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE_DIRS += res classes network-libs
|
||||
|
||||
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# include Android specific java flags - using these instead of what's in rules.mk
|
||||
include $(topsrcdir)/config/android-common.mk
|
||||
|
||||
tools:: FfxCP.apk
|
||||
|
||||
classes.dex: $(JAVAFILES)
|
||||
$(NSINSTALL) -D classes
|
||||
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
|
||||
$(DX) --dex --output=$@ classes
|
||||
|
||||
FfxCP.ap_: $(srcdir)/AndroidManifest.xml
|
||||
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
|
||||
|
||||
FfxCP-unsigned-unaligned.apk: FfxCP.ap_ classes.dex
|
||||
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FfxCP.ap_ -f classes.dex
|
||||
|
||||
FfxCP-unaligned.apk: FfxCP-unsigned-unaligned.apk
|
||||
cp FfxCP-unsigned-unaligned.apk $@
|
||||
ifdef JARSIGNER
|
||||
$(JARSIGNER) $@
|
||||
endif
|
||||
|
||||
FfxCP.apk: FfxCP-unaligned.apk
|
||||
$(ZIPALIGN) -f -v 4 FfxCP-unaligned.apk $@
|
||||
|
||||
export::
|
||||
$(NSINSTALL) -D res
|
||||
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/ffxcp/res && tar -xf -)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package org.mozilla.ffxcp;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int icon=0x7f020000;
|
||||
}
|
||||
public static final class layout {
|
||||
public static final int main=0x7f030000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int app_name=0x7f040001;
|
||||
public static final int hello=0x7f040000;
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-6
|
|
@ -0,0 +1,13 @@
|
|||
package org.mozilla.ffxcp;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class ffxcp extends Activity {
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
}
|
||||
}
|
После Ширина: | Высота: | Размер: 4.0 KiB |
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="hello">Hello World, firefoxcp!</string>
|
||||
<string name="app_name">FirefoxCP</string>
|
||||
</resources>
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mozilla.watcher"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:name=".WatcherMain"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<receiver android:name=".WatcherReceiver">
|
||||
<intent-filter>
|
||||
<action android:value="android.intent.action.BOOT_COMPLETED" android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<category android:value="android.intent.category.HOME" android:name="android.intent.category.HOME"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service android:name="WatcherService">
|
||||
<intent-filter>
|
||||
<action android:name="com.mozilla.watcher.LISTENER_SERVICE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="5" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"></uses-permission>
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This file is auto-generated. DO NOT MODIFY.
|
||||
* Original file: C:\\Users\\Bob\\workspace\\Watcher\\src\\com\\mozilla\\watcher\\IWatcherService.aidl
|
||||
*/
|
||||
package com.mozilla.watcher;
|
||||
public interface IWatcherService extends android.os.IInterface
|
||||
{
|
||||
/** Local-side IPC implementation stub class. */
|
||||
public static abstract class Stub extends android.os.Binder implements com.mozilla.watcher.IWatcherService
|
||||
{
|
||||
private static final java.lang.String DESCRIPTOR = "com.mozilla.watcher.IWatcherService";
|
||||
/** Construct the stub at attach it to the interface. */
|
||||
public Stub()
|
||||
{
|
||||
this.attachInterface(this, DESCRIPTOR);
|
||||
}
|
||||
/**
|
||||
* Cast an IBinder object into an com.mozilla.watcher.IWatcherService interface,
|
||||
* generating a proxy if needed.
|
||||
*/
|
||||
public static com.mozilla.watcher.IWatcherService asInterface(android.os.IBinder obj)
|
||||
{
|
||||
if ((obj==null)) {
|
||||
return null;
|
||||
}
|
||||
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
|
||||
if (((iin!=null)&&(iin instanceof com.mozilla.watcher.IWatcherService))) {
|
||||
return ((com.mozilla.watcher.IWatcherService)iin);
|
||||
}
|
||||
return new com.mozilla.watcher.IWatcherService.Stub.Proxy(obj);
|
||||
}
|
||||
public android.os.IBinder asBinder()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case INTERFACE_TRANSACTION:
|
||||
{
|
||||
reply.writeString(DESCRIPTOR);
|
||||
return true;
|
||||
}
|
||||
case TRANSACTION_UpdateApplication:
|
||||
{
|
||||
data.enforceInterface(DESCRIPTOR);
|
||||
java.lang.String _arg0;
|
||||
_arg0 = data.readString();
|
||||
java.lang.String _arg1;
|
||||
_arg1 = data.readString();
|
||||
java.lang.String _arg2;
|
||||
_arg2 = data.readString();
|
||||
int _arg3;
|
||||
_arg3 = data.readInt();
|
||||
int _result = this.UpdateApplication(_arg0, _arg1, _arg2, _arg3);
|
||||
reply.writeNoException();
|
||||
reply.writeInt(_result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
}
|
||||
private static class Proxy implements com.mozilla.watcher.IWatcherService
|
||||
{
|
||||
private android.os.IBinder mRemote;
|
||||
Proxy(android.os.IBinder remote)
|
||||
{
|
||||
mRemote = remote;
|
||||
}
|
||||
public android.os.IBinder asBinder()
|
||||
{
|
||||
return mRemote;
|
||||
}
|
||||
public java.lang.String getInterfaceDescriptor()
|
||||
{
|
||||
return DESCRIPTOR;
|
||||
}
|
||||
public int UpdateApplication(java.lang.String sPkgName, java.lang.String sPkgFileName, java.lang.String sOutFile, int bReboot) throws android.os.RemoteException
|
||||
{
|
||||
android.os.Parcel _data = android.os.Parcel.obtain();
|
||||
android.os.Parcel _reply = android.os.Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(sPkgName);
|
||||
_data.writeString(sPkgFileName);
|
||||
_data.writeString(sOutFile);
|
||||
_data.writeInt(bReboot);
|
||||
mRemote.transact(Stub.TRANSACTION_UpdateApplication, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
}
|
||||
finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
static final int TRANSACTION_UpdateApplication = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
|
||||
}
|
||||
public int UpdateApplication(java.lang.String sPkgName, java.lang.String sPkgFileName, java.lang.String sOutFile, int bReboot) throws android.os.RemoteException;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Android sutagent for testing.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Clint Talbert <ctalbert@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = Watcher
|
||||
|
||||
JAVAFILES = \
|
||||
IWatcherService.java \
|
||||
RedirOutputThread.java \
|
||||
R.java \
|
||||
WatcherMain.java \
|
||||
WatcherReceiver.java \
|
||||
WatcherService.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
res/drawable-hdpi/icon.png \
|
||||
res/drawable-hdpi/ateamlogo.png \
|
||||
res/drawable-ldpi/icon.png \
|
||||
res/drawable-ldpi/ateamlogo.png \
|
||||
res/drawable-mdpi/icon.png \
|
||||
res/drawable-mdpi/ateamlogo.png \
|
||||
res/layout/main.xml \
|
||||
res/values/strings.xml \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
Watcher.apk \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE_DIRS += res classes network-libs
|
||||
|
||||
JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# include Android specific java flags - using these instead of what's in rules.mk
|
||||
include $(topsrcdir)/config/android-common.mk
|
||||
|
||||
tools:: Watcher.apk
|
||||
|
||||
classes.dex: $(JAVAFILES)
|
||||
$(NSINSTALL) -D classes
|
||||
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
|
||||
$(DX) --dex --output=$@ classes
|
||||
|
||||
Watcher.ap_: $(srcdir)/AndroidManifest.xml
|
||||
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
|
||||
|
||||
Watcher-unsigned-unaligned.apk: Watcher.ap_ classes.dex
|
||||
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z Watcher.ap_ -f classes.dex
|
||||
|
||||
Watcher-unaligned.apk: Watcher-unsigned-unaligned.apk
|
||||
cp Watcher-unsigned-unaligned.apk $@
|
||||
ifdef JARSIGNER
|
||||
$(JARSIGNER) $@
|
||||
endif
|
||||
|
||||
Watcher.apk: Watcher-unaligned.apk
|
||||
$(ZIPALIGN) -f -v 4 Watcher-unaligned.apk $@
|
||||
|
||||
export::
|
||||
$(NSINSTALL) -D res
|
||||
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/watcher/res && tar -xf -)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package com.mozilla.watcher;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int ateamlogo=0x7f020000;
|
||||
public static final int icon=0x7f020001;
|
||||
}
|
||||
public static final class layout {
|
||||
public static final int main=0x7f030000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int app_name=0x7f040001;
|
||||
public static final int foreground_service_started=0x7f040002;
|
||||
public static final int hello=0x7f040000;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android SUTAgent code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Bob Moss.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bob Moss <bmoss@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package com.mozilla.watcher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class RedirOutputThread extends Thread
|
||||
{
|
||||
OutputStream out;
|
||||
InputStream sutErr;
|
||||
InputStream sutOut;
|
||||
Process pProc;
|
||||
String strOutput;
|
||||
|
||||
public RedirOutputThread(Process pProc, OutputStream out)
|
||||
{
|
||||
if (pProc != null)
|
||||
{
|
||||
this.pProc = pProc;
|
||||
sutErr = pProc.getErrorStream(); // Stderr
|
||||
sutOut = pProc.getInputStream(); // Stdout
|
||||
}
|
||||
if (out != null)
|
||||
this.out = out;
|
||||
|
||||
strOutput = "";
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
boolean bStillRunning = true;
|
||||
int nBytesOut = 0;
|
||||
int nBytesErr = 0;
|
||||
int nBytesRead = 0;
|
||||
PrintWriter pOut = null;
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
if (out != null)
|
||||
pOut = new PrintWriter(out);
|
||||
else
|
||||
bStillRunning = true;
|
||||
|
||||
while (bStillRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((nBytesOut = sutOut.available()) > 0)
|
||||
{
|
||||
if (nBytesOut > buffer.length)
|
||||
{
|
||||
buffer = null;
|
||||
System.gc();
|
||||
buffer = new byte[nBytesOut];
|
||||
}
|
||||
nBytesRead = sutOut.read(buffer, 0, nBytesOut);
|
||||
if (nBytesRead == -1)
|
||||
bStillRunning = false;
|
||||
else
|
||||
{
|
||||
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
|
||||
if (pOut != null)
|
||||
{
|
||||
pOut.print(sRep);
|
||||
pOut.flush();
|
||||
}
|
||||
else
|
||||
strOutput += sRep;
|
||||
}
|
||||
}
|
||||
|
||||
if ((nBytesErr = sutErr.available()) > 0)
|
||||
{
|
||||
if (nBytesErr > buffer.length)
|
||||
{
|
||||
buffer = null;
|
||||
System.gc();
|
||||
buffer = new byte[nBytesErr];
|
||||
}
|
||||
nBytesRead = sutErr.read(buffer, 0, nBytesErr);
|
||||
if (nBytesRead == -1)
|
||||
bStillRunning = false;
|
||||
else
|
||||
{
|
||||
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
|
||||
if (pOut != null)
|
||||
{
|
||||
pOut.print(sRep);
|
||||
pOut.flush();
|
||||
}
|
||||
else
|
||||
strOutput += sRep;
|
||||
}
|
||||
}
|
||||
|
||||
bStillRunning = (IsProcRunning(pProc) || (sutOut.available() > 0) || (sutErr.available() > 0));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// Toast.makeText(SUTAgentAndroid.me.getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
pProc.destroy();
|
||||
buffer = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
private boolean IsProcRunning(Process pProc)
|
||||
{
|
||||
boolean bRet = false;
|
||||
@SuppressWarnings("unused")
|
||||
int nExitCode = 0;
|
||||
|
||||
try
|
||||
{
|
||||
nExitCode = pProc.exitValue();
|
||||
}
|
||||
catch (IllegalThreadStateException z)
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
|
||||
return(bRet);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.mozilla.watcher;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class WatcherMain extends Activity {
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.mozilla.watcher;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
// import android.os.Debug;
|
||||
|
||||
public class WatcherReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// Debug.waitForDebugger();
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra("command", "start");
|
||||
serviceIntent.setAction("com.mozilla.watcher.LISTENER_SERVICE");
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,914 @@
|
|||
package com.mozilla.watcher;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class WatcherService extends Service
|
||||
{
|
||||
String sErrorPrefix = "##Installer Error## ";
|
||||
String currentDir = "/";
|
||||
String sPingTarget = "";
|
||||
long lDelay = 60000;
|
||||
long lPeriod = 300000;
|
||||
int nMaxStrikes = 3;
|
||||
Process pProc;
|
||||
Context myContext = null;
|
||||
Timer myTimer = null;
|
||||
private PowerManager.WakeLock pwl = null;
|
||||
public static final int NOTIFICATION_ID = 1964;
|
||||
boolean bInstalling = false;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final Class[] mStartForegroundSignature = new Class[] {
|
||||
int.class, Notification.class};
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final Class[] mStopForegroundSignature = new Class[] {
|
||||
boolean.class};
|
||||
|
||||
private NotificationManager mNM;
|
||||
private Method mStartForeground;
|
||||
private Method mStopForeground;
|
||||
private Object[] mStartForegroundArgs = new Object[2];
|
||||
private Object[] mStopForegroundArgs = new Object[1];
|
||||
|
||||
|
||||
private IWatcherService.Stub stub = new IWatcherService.Stub() {
|
||||
@Override
|
||||
public int UpdateApplication(String sAppName, String sFileName, String sOutFile, int bReboot) throws RemoteException
|
||||
{
|
||||
return UpdtApp(sAppName, sFileName, sOutFile, bReboot);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return stub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
|
||||
myContext = this;
|
||||
|
||||
getKeyGuardAndWakeLock();
|
||||
|
||||
File dir = getFilesDir();
|
||||
File iniFile = new File(dir, "watcher.ini");
|
||||
String sIniFile = iniFile.getAbsolutePath();
|
||||
String sHold = "";
|
||||
|
||||
this.sPingTarget = GetIniData("watcher", "PingTarget", sIniFile, "www.mozilla.org");
|
||||
sHold = GetIniData("watcher", "delay", sIniFile, "60000");
|
||||
this.lDelay = Long.parseLong(sHold.trim());
|
||||
sHold = GetIniData("watcher", "period", sIniFile,"300000");
|
||||
this.lPeriod = Long.parseLong(sHold.trim());
|
||||
sHold = GetIniData("watcher", "strikes", sIniFile,"3");
|
||||
this.nMaxStrikes = Integer.parseInt(sHold.trim());
|
||||
|
||||
doToast("WatcherService created");
|
||||
}
|
||||
|
||||
public String GetIniData(String sSection, String sKey, String sFile, String sDefault)
|
||||
{
|
||||
String sRet = sDefault;
|
||||
String sComp = "";
|
||||
String sLine = "";
|
||||
boolean bFound = false;
|
||||
BufferedReader in = null;
|
||||
String sTmpFileName = fixFileName(sFile);
|
||||
|
||||
try {
|
||||
in = new BufferedReader(new FileReader(sTmpFileName));
|
||||
sComp = "[" + sSection + "]";
|
||||
while ((sLine = in.readLine()) != null)
|
||||
{
|
||||
if (sLine.equalsIgnoreCase(sComp))
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
sComp = (sKey + " =").toLowerCase();
|
||||
while ((sLine = in.readLine()) != null)
|
||||
{
|
||||
if (sLine.toLowerCase().contains(sComp))
|
||||
{
|
||||
String [] temp = null;
|
||||
temp = sLine.split("=");
|
||||
if (temp != null)
|
||||
{
|
||||
if (temp.length > 1)
|
||||
sRet = temp[1].trim();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
sComp = e.toString();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sComp = e.toString();
|
||||
}
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
private void handleCommand(Intent intent)
|
||||
{
|
||||
String sCmd = intent.getStringExtra("command");
|
||||
|
||||
// Debug.waitForDebugger();
|
||||
|
||||
if (sCmd != null)
|
||||
{
|
||||
if (sCmd.equalsIgnoreCase("updt"))
|
||||
{
|
||||
String sPkgName = intent.getStringExtra("pkgName");
|
||||
String sPkgFile = intent.getStringExtra("pkgFile");
|
||||
String sOutFile = intent.getStringExtra("outFile");
|
||||
boolean bReboot = intent.getBooleanExtra("reboot", true);
|
||||
int nReboot = bReboot ? 1 : 0;
|
||||
SendNotification("WatcherService updating " + sPkgName + " using file " + sPkgFile, "WatcherService updating " + sPkgName + " using file " + sPkgFile);
|
||||
|
||||
UpdateApplication worker = new UpdateApplication(sPkgName, sPkgFile, sOutFile, nReboot);
|
||||
}
|
||||
else if (sCmd.equalsIgnoreCase("start"))
|
||||
{
|
||||
doToast("WatcherService started");
|
||||
myTimer = new Timer();
|
||||
myTimer.scheduleAtFixedRate(new MyTime(), lDelay, lPeriod);
|
||||
}
|
||||
else
|
||||
{
|
||||
doToast("WatcherService unknown command");
|
||||
}
|
||||
}
|
||||
else
|
||||
doToast("WatcherService created");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
handleCommand(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
handleCommand(intent);
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
doToast("WatcherService destroyed");
|
||||
if (pwl != null)
|
||||
pwl.release();
|
||||
stopForegroundCompat(R.string.foreground_service_started);
|
||||
}
|
||||
|
||||
protected void getKeyGuardAndWakeLock()
|
||||
{
|
||||
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
|
||||
Thread t = new Thread() {
|
||||
public void run() {
|
||||
// Keep phone from locking or remove lock on screen
|
||||
KeyguardManager km = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
|
||||
if (km != null)
|
||||
{
|
||||
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("watcher");
|
||||
if (kl != null)
|
||||
kl.disableKeyguard();
|
||||
}
|
||||
|
||||
// No sleeping on the job
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
if (pm != null)
|
||||
{
|
||||
pwl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "watcher");
|
||||
if (pwl != null)
|
||||
pwl.acquire();
|
||||
}
|
||||
|
||||
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||
try {
|
||||
mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature);
|
||||
mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
// Running on an older platform.
|
||||
mStartForeground = mStopForeground = null;
|
||||
}
|
||||
Notification notification = new Notification();
|
||||
startForegroundCompat(R.string.foreground_service_started, notification);
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new startForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
void startForegroundCompat(int id, Notification notification) {
|
||||
// If we have the new startForeground API, then use it.
|
||||
if (mStartForeground != null) {
|
||||
mStartForegroundArgs[0] = Integer.valueOf(id);
|
||||
mStartForegroundArgs[1] = notification;
|
||||
try {
|
||||
mStartForeground.invoke(this, mStartForegroundArgs);
|
||||
} catch (InvocationTargetException e) {
|
||||
// Should not happen.
|
||||
Log.w("ApiDemos", "Unable to invoke startForeground", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Should not happen.
|
||||
Log.w("ApiDemos", "Unable to invoke startForeground", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall back on the old API.
|
||||
setForeground(true);
|
||||
mNM.notify(id, notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new stopForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
void stopForegroundCompat(int id) {
|
||||
// If we have the new stopForeground API, then use it.
|
||||
if (mStopForeground != null) {
|
||||
mStopForegroundArgs[0] = Boolean.TRUE;
|
||||
try {
|
||||
mStopForeground.invoke(this, mStopForegroundArgs);
|
||||
} catch (InvocationTargetException e) {
|
||||
// Should not happen.
|
||||
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Should not happen.
|
||||
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall back on the old API. Note to cancel BEFORE changing the
|
||||
// foreground state, since we could be killed at that point.
|
||||
mNM.cancel(id);
|
||||
setForeground(false);
|
||||
}
|
||||
|
||||
public void doToast(String sMsg)
|
||||
{
|
||||
Toast toast = Toast.makeText(this, sMsg, Toast.LENGTH_LONG);
|
||||
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 100);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
public void CheckMem() {
|
||||
System.gc();
|
||||
long lFreeMemory = Runtime.getRuntime().freeMemory();
|
||||
long lTotMemory = Runtime.getRuntime().totalMemory();
|
||||
long lMaxMemory = Runtime.getRuntime().maxMemory();
|
||||
|
||||
SendNotification("Memory Check", "Free: " + lFreeMemory + "Total: " + lTotMemory + "Max: " + lMaxMemory);
|
||||
}
|
||||
|
||||
public int UpdtApp(String sPkgName, String sPkgFileName, String sOutFile, int bReboot)
|
||||
{
|
||||
int nRet = 1;
|
||||
int lcv = 0;
|
||||
String sRet = "";
|
||||
|
||||
// Debug.waitForDebugger();
|
||||
|
||||
FileOutputStream f = null;
|
||||
|
||||
try {
|
||||
SendNotification("Killing " + sPkgName, "Step 1: Kill " + sPkgName + " if running");
|
||||
while (!IsProcessDead(sPkgName) && (lcv < 5)) {
|
||||
if (KillProcess(sPkgName, null).startsWith("Successfully"))
|
||||
break;
|
||||
else
|
||||
lcv++;
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
|
||||
CheckMem();
|
||||
|
||||
if ((sOutFile != null) && (sOutFile.length() > 0)) {
|
||||
File outFile = new File(sOutFile);
|
||||
if (outFile.exists() && outFile.canWrite()) {
|
||||
f = new FileOutputStream(outFile, true);
|
||||
} else {
|
||||
SendNotification("File not found or cannot write to " + sOutFile, "File not found or cannot write to " + sOutFile);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (FileNotFoundException e) {
|
||||
SendNotification("File not found " + sOutFile, "Couldn't open " + sOutFile + " " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
SendNotification("Security excepetion for " + sOutFile, "Exception message " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ((sPkgName != null) && (sPkgName.length() > 0))
|
||||
{
|
||||
SendNotification("Uninstalling " + sPkgName, "Step 2: Uninstall " + sPkgName);
|
||||
sRet = UnInstallApp(sPkgName, null);
|
||||
CheckMem();
|
||||
if ((sRet.length() > 0) && (f != null))
|
||||
{
|
||||
try {
|
||||
f.write(sRet.getBytes());
|
||||
f.flush();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((sPkgFileName != null) && (sPkgFileName.length() > 0))
|
||||
{
|
||||
SendNotification("Installing " + sPkgFileName, "Step 3: Install " + sPkgFileName);
|
||||
sRet = InstallApp(sPkgFileName, null);
|
||||
SendNotification("Installed " + sPkgFileName, "" + sRet);
|
||||
CheckMem();
|
||||
if ((sRet.length() > 0) && (f != null))
|
||||
{
|
||||
try {
|
||||
f.write(sRet.getBytes());
|
||||
f.flush();
|
||||
f.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bReboot > 0)
|
||||
RunReboot(null);
|
||||
|
||||
return(nRet);
|
||||
}
|
||||
|
||||
public boolean GetProcessInfo(String sProcName)
|
||||
{
|
||||
boolean bRet = false;
|
||||
ActivityManager aMgr = (ActivityManager) getApplicationContext().getSystemService(Activity.ACTIVITY_SERVICE);
|
||||
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
|
||||
int nProcs = lProcesses.size();
|
||||
int lcv = 0;
|
||||
String strProcName = "";
|
||||
|
||||
for (lcv = 0; lcv < nProcs; lcv++)
|
||||
{
|
||||
strProcName = lProcesses.get(lcv).processName;
|
||||
if (strProcName.contains(sProcName))
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (bRet);
|
||||
}
|
||||
|
||||
public String RunReboot(OutputStream out)
|
||||
{
|
||||
String sRet = "";
|
||||
String [] theArgs = new String [3];
|
||||
|
||||
theArgs[0] = "su";
|
||||
theArgs[1] = "-c";
|
||||
theArgs[2] = "reboot";
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
|
||||
outThrd.start();
|
||||
outThrd.join(10000);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sRet = e.getMessage();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
public String KillProcess(String sProcName, OutputStream out)
|
||||
{
|
||||
String [] theArgs = new String [3];
|
||||
|
||||
theArgs[0] = "su";
|
||||
theArgs[1] = "-c";
|
||||
theArgs[2] = "kill";
|
||||
|
||||
String sRet = sErrorPrefix + "Unable to kill " + sProcName + "\n";
|
||||
ActivityManager aMgr = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
|
||||
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses();
|
||||
int lcv = 0;
|
||||
String strProcName = "";
|
||||
int nPID = 0;
|
||||
|
||||
for (lcv = 0; lcv < lProcesses.size(); lcv++)
|
||||
{
|
||||
if (lProcesses.get(lcv).processName.contains(sProcName))
|
||||
{
|
||||
strProcName = lProcesses.get(lcv).processName;
|
||||
nPID = lProcesses.get(lcv).pid;
|
||||
sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n";
|
||||
|
||||
theArgs[2] += " " + nPID;
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
|
||||
outThrd.start();
|
||||
outThrd.join(5000);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sRet = e.getMessage();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Give the messages a chance to be processed
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nPID > 0)
|
||||
{
|
||||
sRet = "Successfully killed " + nPID + " " + strProcName + "\n";
|
||||
lProcesses = aMgr.getRunningAppProcesses();
|
||||
for (lcv = 0; lcv < lProcesses.size(); lcv++)
|
||||
{
|
||||
if (lProcesses.get(lcv).processName.contains(sProcName))
|
||||
{
|
||||
sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
public String GetAppRoot(String AppName)
|
||||
{
|
||||
String sRet = sErrorPrefix + " internal error [no context]";
|
||||
Context ctx = getApplicationContext();
|
||||
|
||||
if (ctx != null)
|
||||
{
|
||||
try {
|
||||
Context appCtx = ctx.createPackageContext(AppName, 0);
|
||||
ContextWrapper appCtxW = new ContextWrapper(appCtx);
|
||||
sRet = appCtxW.getPackageResourcePath();
|
||||
appCtxW = null;
|
||||
appCtx = null;
|
||||
ctx = null;
|
||||
System.gc();
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return(sRet);
|
||||
}
|
||||
|
||||
public boolean IsProcessDead(String sProcName)
|
||||
{
|
||||
boolean bRet = true;
|
||||
ActivityManager aMgr = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
|
||||
List <ActivityManager.RunningAppProcessInfo> lProcesses = aMgr.getRunningAppProcesses(); // .getProcessesInErrorState();
|
||||
int lcv = 0;
|
||||
|
||||
if (lProcesses != null)
|
||||
{
|
||||
for (lcv = 0; lcv < lProcesses.size(); lcv++)
|
||||
{
|
||||
if (lProcesses.get(lcv).processName.contentEquals(sProcName))
|
||||
{
|
||||
bRet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (bRet);
|
||||
}
|
||||
|
||||
public String fixFileName(String fileName)
|
||||
{
|
||||
String sRet = "";
|
||||
String sTmpFileName = "";
|
||||
|
||||
sRet = fileName.replace('\\', '/');
|
||||
|
||||
if (sRet.startsWith("/"))
|
||||
sTmpFileName = sRet;
|
||||
else
|
||||
sTmpFileName = currentDir + "/" + sRet;
|
||||
|
||||
sRet = sTmpFileName.replace('\\', '/');
|
||||
sTmpFileName = sRet;
|
||||
sRet = sTmpFileName.replace("//", "/");
|
||||
|
||||
return(sRet);
|
||||
}
|
||||
|
||||
public String GetTmpDir()
|
||||
{
|
||||
String sRet = "";
|
||||
Context ctx = getApplicationContext();
|
||||
File dir = ctx.getFilesDir();
|
||||
ctx = null;
|
||||
try {
|
||||
sRet = dir.getCanonicalPath();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return(sRet);
|
||||
}
|
||||
|
||||
public String UnInstallApp(String sApp, OutputStream out)
|
||||
{
|
||||
String sRet = "";
|
||||
String [] theArgs = new String [3];
|
||||
|
||||
theArgs[0] = "su";
|
||||
theArgs[1] = "-c";
|
||||
theArgs[2] = "pm uninstall " + sApp + ";exit";
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
|
||||
outThrd.start();
|
||||
outThrd.join(60000);
|
||||
int nRet = pProc.exitValue();
|
||||
sRet = "\nuninst complete [" + nRet + "]";
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sRet = e.getMessage();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
public String InstallApp(String sApp, OutputStream out)
|
||||
{
|
||||
String sRet = "";
|
||||
String sHold = "";
|
||||
String [] theArgs = new String [3];
|
||||
|
||||
theArgs[0] = "su";
|
||||
theArgs[1] = "-c";
|
||||
theArgs[2] = "pm install " + sApp + ";exit";
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
|
||||
outThrd.start();
|
||||
outThrd.join(180000);
|
||||
int nRet = pProc.exitValue();
|
||||
sRet += "\ninstall complete [" + nRet + "]";
|
||||
sHold = outThrd.strOutput;
|
||||
sRet += "\nSuccess";
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sRet = e.getMessage();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
private String SendPing(String sIPAddr)
|
||||
{
|
||||
Process pProc;
|
||||
String sRet = "";
|
||||
String [] theArgs = new String [4];
|
||||
boolean bStillRunning = true;
|
||||
int nBytesOut = 0;
|
||||
int nBytesErr = 0;
|
||||
int nBytesRead = 0;
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
theArgs[0] = "ping";
|
||||
theArgs[1] = "-c";
|
||||
theArgs[2] = "3";
|
||||
theArgs[3] = sIPAddr;
|
||||
|
||||
try
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs);
|
||||
|
||||
InputStream sutOut = pProc.getInputStream();
|
||||
InputStream sutErr = pProc.getErrorStream();
|
||||
|
||||
while (bStillRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((nBytesOut = sutOut.available()) > 0)
|
||||
{
|
||||
if (nBytesOut > buffer.length)
|
||||
{
|
||||
buffer = null;
|
||||
System.gc();
|
||||
buffer = new byte[nBytesOut];
|
||||
}
|
||||
nBytesRead = sutOut.read(buffer, 0, nBytesOut);
|
||||
if (nBytesRead == -1)
|
||||
bStillRunning = false;
|
||||
else
|
||||
{
|
||||
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
|
||||
sRet += sRep;
|
||||
sRep = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ((nBytesErr = sutErr.available()) > 0)
|
||||
{
|
||||
if (nBytesErr > buffer.length)
|
||||
{
|
||||
buffer = null;
|
||||
System.gc();
|
||||
buffer = new byte[nBytesErr];
|
||||
}
|
||||
nBytesRead = sutErr.read(buffer, 0, nBytesErr);
|
||||
if (nBytesRead == -1)
|
||||
bStillRunning = false;
|
||||
else
|
||||
{
|
||||
String sRep = new String(buffer,0,nBytesRead).replace("\n", "\r\n");
|
||||
sRet += sRep;
|
||||
sRep = null;
|
||||
}
|
||||
}
|
||||
|
||||
bStillRunning = (IsProcRunning(pProc) || (sutOut.available() > 0) || (sutErr.available() > 0));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ((bStillRunning == true) && (nBytesErr == 0) && (nBytesOut == 0))
|
||||
{
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pProc.destroy();
|
||||
pProc = null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
sRet = e.getMessage();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
private boolean IsProcRunning(Process pProc)
|
||||
{
|
||||
boolean bRet = false;
|
||||
@SuppressWarnings("unused")
|
||||
int nExitCode = 0;
|
||||
|
||||
try
|
||||
{
|
||||
nExitCode = pProc.exitValue();
|
||||
}
|
||||
catch (IllegalThreadStateException z)
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return(bRet);
|
||||
}
|
||||
|
||||
private class UpdateApplication implements Runnable {
|
||||
Thread runner;
|
||||
String msPkgName = "";
|
||||
String msPkgFileName = "";
|
||||
String msOutFile = "";
|
||||
int mbReboot = 0;
|
||||
|
||||
public UpdateApplication(String sPkgName, String sPkgFileName, String sOutFile, int bReboot) {
|
||||
runner = new Thread(this);
|
||||
msPkgName = sPkgName;
|
||||
msPkgFileName = sPkgFileName;
|
||||
msOutFile = sOutFile;
|
||||
mbReboot = bReboot;
|
||||
runner.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
bInstalling = true;
|
||||
UpdtApp(msPkgName, msPkgFileName, msOutFile, mbReboot);
|
||||
bInstalling = false;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyTime extends TimerTask
|
||||
{
|
||||
int nStrikes = 0;
|
||||
|
||||
public MyTime()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (bInstalling)
|
||||
return;
|
||||
|
||||
// See if the network is up, if not after three failures reboot
|
||||
String sRet = SendPing(sPingTarget);
|
||||
if (!sRet.contains("3 received"))
|
||||
{
|
||||
if (nMaxStrikes > 0)
|
||||
{
|
||||
if (++nStrikes >= nMaxStrikes)
|
||||
RunReboot(null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nStrikes = 0;
|
||||
}
|
||||
sRet = null;
|
||||
|
||||
String sProgramName = "com.mozilla.SUTAgentAndroid";
|
||||
PackageManager pm = myContext.getPackageManager();
|
||||
|
||||
// Debug.waitForDebugger();
|
||||
|
||||
if (!GetProcessInfo(sProgramName))
|
||||
{
|
||||
Intent agentIntent = new Intent();
|
||||
agentIntent.setPackage(sProgramName);
|
||||
agentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
agentIntent.setAction(Intent.ACTION_MAIN);
|
||||
try {
|
||||
PackageInfo pi = pm.getPackageInfo(sProgramName, PackageManager.GET_ACTIVITIES | PackageManager.GET_INTENT_FILTERS);
|
||||
ActivityInfo [] ai = pi.activities;
|
||||
for (int i = 0; i < ai.length; i++)
|
||||
{
|
||||
ActivityInfo a = ai[i];
|
||||
if (a.name.length() > 0)
|
||||
{
|
||||
agentIntent.setClassName(a.packageName, a.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
try
|
||||
{
|
||||
myContext.startActivity(agentIntent);
|
||||
}
|
||||
catch(ActivityNotFoundException anf)
|
||||
{
|
||||
anf.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendNotification(String tickerText, String expandedText) {
|
||||
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
int icon = R.drawable.ateamlogo;
|
||||
long when = System.currentTimeMillis();
|
||||
|
||||
Notification notification = new Notification(icon, tickerText, when);
|
||||
|
||||
notification.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||
notification.defaults |= Notification.DEFAULT_SOUND;
|
||||
// notification.defaults |= Notification.DEFAULT_VIBRATE;
|
||||
notification.defaults |= Notification.DEFAULT_LIGHTS;
|
||||
|
||||
Context context = getApplicationContext();
|
||||
|
||||
// Intent to launch an activity when the extended text is clicked
|
||||
Intent intent = new Intent(this, WatcherService.class);
|
||||
PendingIntent launchIntent = PendingIntent.getActivity(context, 0, intent, 0);
|
||||
|
||||
notification.setLatestEventInfo(context, tickerText, expandedText, launchIntent);
|
||||
|
||||
notificationManager.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
|
||||
private void CancelNotification() {
|
||||
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-5
|
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 4.0 KiB |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="hello">Hello World, WatcherMain!</string>
|
||||
<string name="app_name">watcher</string>
|
||||
<string name="foreground_service_started">Foreground Service Started</string>
|
||||
|
||||
</resources>
|
|
@ -240,6 +240,9 @@ stage-mozmill: make-stage-dir
|
|||
|
||||
stage-android: make-stage-dir
|
||||
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/sutAgentAndroid.apk $(PKG_STAGE)/bin
|
||||
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/watcher/Watcher.apk $(PKG_STAGE)/bin
|
||||
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/fencp/FenCP.apk $(PKG_STAGE)/bin
|
||||
$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/ffxcp/FfxCP.apk $(PKG_STAGE)/bin
|
||||
|
||||
stage-jetpack: make-stage-dir
|
||||
$(NSINSTALL) $(topsrcdir)/testing/jetpack/jetpack-location.txt $(PKG_STAGE)/jetpack
|
||||
|
|