mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Move application bootstrap logic from widgets to project template.
This commit is contained in:
@@ -51,18 +51,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
android.libraryVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
output.packageLibrary.exclude('libs/android-runtime.jar')
|
||||
output.packageLibrary.exclude('libs/android-binding-generator.jar')
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.android.support:support-v4:+'
|
||||
compile files('extlibs/android-binding-generator.jar')
|
||||
compile files('extlibs/android-runtime.jar')
|
||||
}
|
||||
|
||||
task cleanDistDir (type: Delete) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,414 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import java.net.CookieManager;
|
||||
|
||||
public class Async
|
||||
{
|
||||
public interface CompleteCallback
|
||||
{
|
||||
void onComplete(Object result, Object context);
|
||||
}
|
||||
|
||||
public static void DownloadImage(String url, CompleteCallback callback, Object context)
|
||||
{
|
||||
new ImageDownloadTask(callback, context).execute(url);
|
||||
}
|
||||
|
||||
public static class Http
|
||||
{
|
||||
private static final String DeleteMethod = "DELETE";
|
||||
private static final String GetMethod = "GET";
|
||||
private static CookieManager cookieManager;
|
||||
|
||||
public static class KeyValuePair
|
||||
{
|
||||
public String key;
|
||||
public String value;
|
||||
|
||||
public KeyValuePair(String key, String value)
|
||||
{
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequestOptions
|
||||
{
|
||||
public String url;
|
||||
public String method;
|
||||
public ArrayList<KeyValuePair> headers;
|
||||
public String content;
|
||||
public int timeout = -1;
|
||||
public int screenWidth = -1;
|
||||
public int screenHeight = -1;
|
||||
|
||||
public void addHeaders(HttpURLConnection connection)
|
||||
{
|
||||
if (this.headers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (KeyValuePair pair : this.headers)
|
||||
{
|
||||
connection.addRequestProperty(pair.key.toString(), pair.value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void writeContent(HttpURLConnection connection, Stack<Closeable> openedStreams) throws IOException
|
||||
{
|
||||
if (this.content == null || this.content.getClass() != String.class)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream outStream = connection.getOutputStream();
|
||||
openedStreams.push(outStream);
|
||||
|
||||
OutputStreamWriter writer = new java.io.OutputStreamWriter(outStream);
|
||||
openedStreams.push(writer);
|
||||
|
||||
writer.write((String) this.content);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequestResult
|
||||
{
|
||||
public static final class ByteArrayOutputStream2 extends java.io.ByteArrayOutputStream
|
||||
{
|
||||
public ByteArrayOutputStream2()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream2(int size)
|
||||
{
|
||||
super(size);
|
||||
}
|
||||
|
||||
/** Returns the internal buffer of this ByteArrayOutputStream, without copying. */
|
||||
public synchronized byte[] buf()
|
||||
{
|
||||
return this.buf;
|
||||
}
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream raw;
|
||||
public ArrayList<KeyValuePair> headers = new ArrayList<KeyValuePair>();
|
||||
public int statusCode;
|
||||
public String responseAsString;
|
||||
public Bitmap responseAsImage;
|
||||
public Exception error;
|
||||
|
||||
public void getHeaders(HttpURLConnection connection)
|
||||
{
|
||||
Map<String, List<String>> headers = connection.getHeaderFields();
|
||||
if (headers == null)
|
||||
{
|
||||
// no headers, this may happen if there is no internet connection currently available
|
||||
return;
|
||||
}
|
||||
|
||||
int size = headers.size();
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size - 1; i++)
|
||||
{
|
||||
String key = connection.getHeaderFieldKey(i);
|
||||
String value = connection.getHeaderField(key);
|
||||
this.headers.add(new KeyValuePair(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
public void readResponseStream(HttpURLConnection connection, Stack<Closeable> openedStreams, RequestOptions options) throws IOException
|
||||
{
|
||||
this.statusCode = connection.getResponseCode();
|
||||
|
||||
int contentLength = connection.getContentLength();
|
||||
|
||||
InputStream inStream;
|
||||
if (this.statusCode >= 400)
|
||||
{
|
||||
inStream = connection.getErrorStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
inStream = connection.getInputStream();
|
||||
}
|
||||
|
||||
if (inStream == null)
|
||||
{
|
||||
// inStream is null when receiving status code 401 or 407
|
||||
// see this thread for more information http://stackoverflow.com/a/24986433
|
||||
return;
|
||||
}
|
||||
|
||||
openedStreams.push(inStream);
|
||||
|
||||
BufferedInputStream buffer = new java.io.BufferedInputStream(inStream, 4096);
|
||||
openedStreams.push(buffer);
|
||||
|
||||
ByteArrayOutputStream2 responseStream = contentLength != -1 ? new ByteArrayOutputStream2(contentLength) : new ByteArrayOutputStream2();
|
||||
openedStreams.push(responseStream);
|
||||
|
||||
byte[] buff = new byte[4096];
|
||||
int read = -1;
|
||||
while ((read = buffer.read(buff, 0, buff.length)) != -1)
|
||||
{
|
||||
responseStream.write(buff, 0, read);
|
||||
}
|
||||
|
||||
this.raw = responseStream;
|
||||
buff = null;
|
||||
|
||||
// make the byte array conversion here, not in the JavaScript
|
||||
// world for better performance
|
||||
// since we do not have some explicit way to determine whether
|
||||
// the content-type is image
|
||||
try
|
||||
{
|
||||
// TODO: Generally this approach will not work for very
|
||||
// large files
|
||||
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
|
||||
// check the size of the bitmap first
|
||||
BitmapFactory.decodeByteArray(responseStream.buf(), 0, responseStream.size(), bitmapOptions);
|
||||
if (bitmapOptions.outWidth > 0 && bitmapOptions.outHeight > 0)
|
||||
{
|
||||
int scale = 1;
|
||||
final int height = bitmapOptions.outHeight;
|
||||
final int width = bitmapOptions.outWidth;
|
||||
|
||||
if (bitmapOptions.outWidth > options.screenWidth || bitmapOptions.outHeight > options.screenHeight)
|
||||
{
|
||||
final int halfHeight = height / 2;
|
||||
final int halfWidth = width / 2;
|
||||
|
||||
// scale down the image since it is larger than the
|
||||
// screen resolution
|
||||
while ((halfWidth / scale) > options.screenWidth && (halfHeight / scale) > options.screenHeight)
|
||||
{
|
||||
scale *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
bitmapOptions.inJustDecodeBounds = false;
|
||||
bitmapOptions.inSampleSize = scale;
|
||||
this.responseAsImage = BitmapFactory.decodeByteArray(responseStream.buf(), 0, responseStream.size(), bitmapOptions);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// bitmap decoding failed, the stream is not an image
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (this.responseAsImage == null)
|
||||
{
|
||||
// convert to string
|
||||
this.responseAsString = responseStream.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void MakeRequest(RequestOptions options, CompleteCallback callback, Object context)
|
||||
{
|
||||
if (options.screenWidth < 0 || options.screenHeight < 0)
|
||||
{
|
||||
DisplayMetrics metrics = appContext.getResources().getDisplayMetrics();
|
||||
options.screenWidth = metrics.widthPixels;
|
||||
options.screenHeight = metrics.heightPixels;
|
||||
}
|
||||
|
||||
if (cookieManager == null)
|
||||
{
|
||||
cookieManager = new CookieManager();
|
||||
CookieHandler.setDefault(cookieManager);
|
||||
}
|
||||
|
||||
new HttpRequestTask(callback, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, options);
|
||||
}
|
||||
|
||||
private static Application appContext;
|
||||
|
||||
public static void setApplicationContext(Application app)
|
||||
{
|
||||
appContext = app;
|
||||
}
|
||||
|
||||
static class HttpRequestTask extends AsyncTask<RequestOptions, Void, RequestResult>
|
||||
{
|
||||
private CompleteCallback callback;
|
||||
private Object context;
|
||||
|
||||
public HttpRequestTask(CompleteCallback callback, Object context)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RequestResult doInBackground(RequestOptions... params)
|
||||
{
|
||||
RequestResult result = new RequestResult();
|
||||
Stack<Closeable> openedStreams = new Stack<Closeable>();
|
||||
|
||||
try
|
||||
{
|
||||
RequestOptions options = params[0];
|
||||
URL url = new URL(options.url);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
// set the request method
|
||||
String requestMethod = options.method != null ? options.method.toUpperCase() : GetMethod;
|
||||
connection.setRequestMethod(requestMethod);
|
||||
|
||||
// add the headers
|
||||
options.addHeaders(connection);
|
||||
|
||||
// apply timeout
|
||||
if (options.timeout > 0)
|
||||
{
|
||||
connection.setConnectTimeout(options.timeout);
|
||||
}
|
||||
|
||||
// Do not attempt to write the content (body) for DELETE method, Java will throw directly
|
||||
if (requestMethod != DeleteMethod)
|
||||
{
|
||||
options.writeContent(connection, openedStreams);
|
||||
}
|
||||
|
||||
// close the opened streams (saves copy-paste implementation
|
||||
// in each method that throws IOException)
|
||||
this.closeOpenedStreams(openedStreams);
|
||||
|
||||
connection.connect();
|
||||
|
||||
// build the result
|
||||
result.getHeaders(connection);
|
||||
result.readResponseStream(connection, openedStreams, options);
|
||||
|
||||
// close the opened streams (saves copy-paste implementation
|
||||
// in each method that throws IOException)
|
||||
this.closeOpenedStreams(openedStreams);
|
||||
|
||||
connection.disconnect();
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e) // TODO: Catch all exceptions?
|
||||
{
|
||||
e.printStackTrace();
|
||||
result.error = e;
|
||||
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
this.closeOpenedStreams(openedStreams);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// TODO: Java rules - what to do here???
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(final RequestResult result)
|
||||
{
|
||||
this.callback.onComplete(result, this.context);
|
||||
}
|
||||
|
||||
private void closeOpenedStreams(Stack<Closeable> streams) throws IOException
|
||||
{
|
||||
while (streams.size() > 0)
|
||||
{
|
||||
Closeable stream = streams.pop();
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ImageDownloadTask extends AsyncTask<String, Void, Bitmap>
|
||||
{
|
||||
private CompleteCallback callback;
|
||||
private Object context;
|
||||
|
||||
public ImageDownloadTask(CompleteCallback callback, Object context)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
protected Bitmap doInBackground(String... params)
|
||||
{
|
||||
InputStream stream = null;
|
||||
try
|
||||
{
|
||||
stream = new java.net.URL(params[0]).openStream();
|
||||
Bitmap bmp = BitmapFactory.decodeStream(stream);
|
||||
return bmp;
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(final Bitmap result)
|
||||
{
|
||||
this.callback.onComplete(result, this.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.tns.Logger;
|
||||
import com.tns.ExtractPolicy;
|
||||
import com.tns.FileExtractor;
|
||||
|
||||
public class DefaultExtractPolicy implements ExtractPolicy
|
||||
{
|
||||
private final Logger logger;
|
||||
|
||||
private final static String ASSETS_THUMB_FILENAME = "assetsThumb";
|
||||
|
||||
public DefaultExtractPolicy(Logger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public boolean shouldExtract(android.content.Context context)
|
||||
{
|
||||
String assetsThumb = generateAssetsThumb(context);
|
||||
if (assetsThumb != null)
|
||||
{
|
||||
String assetsThumbFilePath = context.getFilesDir().getPath() + File.separatorChar + ASSETS_THUMB_FILENAME;
|
||||
String oldAssetsThumb = getCachedAssetsThumb(assetsThumbFilePath);
|
||||
if (oldAssetsThumb == null || !assetsThumb.equals(oldAssetsThumb))
|
||||
{
|
||||
saveNewAssetsThumb(assetsThumb, assetsThumbFilePath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean forceOverwrite()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public FileExtractor extractor()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private String generateAssetsThumb(Context context)
|
||||
{
|
||||
try
|
||||
{
|
||||
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
int code = packageInfo.versionCode;
|
||||
long updateTime = packageInfo.lastUpdateTime;
|
||||
return String.valueOf(updateTime) + "-" + String.valueOf(code);
|
||||
}
|
||||
catch (PackageManager.NameNotFoundException e)
|
||||
{
|
||||
logger.write("Error while getting current assets thumb");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getCachedAssetsThumb(String assetsThumbFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
File cachedThumbFile = new File(assetsThumbFilePath);
|
||||
if (cachedThumbFile.exists())
|
||||
{
|
||||
FileInputStream in = new FileInputStream(cachedThumbFile);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String cachedThumb = reader.readLine();
|
||||
reader.close();
|
||||
in.close();
|
||||
return cachedThumb;
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
logger.write("Error while getting current assets thumb");
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.write("Error while getting current asstes thumb");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void saveNewAssetsThumb(String newThumb, String assetsThumbFile)
|
||||
{
|
||||
File cachedThumbFile = new File(assetsThumbFile);
|
||||
try
|
||||
{
|
||||
FileOutputStream out = new FileOutputStream(cachedThumbFile, false);
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
|
||||
try
|
||||
{
|
||||
writer.write(newThumb);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
}
|
||||
finally
|
||||
{
|
||||
writer.close();
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
logger.write("Error while writting current assets thumb");
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.write("Error while writting current assets thumb");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.PendingIntent.CanceledException;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
class ErrorReport
|
||||
{
|
||||
public static final String ERROR_FILE_NAME = "hasError";
|
||||
private final Activity activity;
|
||||
|
||||
private final static String EXTRA_NATIVESCRIPT_ERROR_REPORT = "NativeScriptErrorMessage";
|
||||
private final static String EXTRA_ERROR_REPORT_MSG = "msg";
|
||||
private final static int EXTRA_ERROR_REPORT_VALUE = 1;
|
||||
|
||||
public ErrorReport(Activity activity)
|
||||
{
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
static boolean startActivity(final Context context, String errorMessage)
|
||||
{
|
||||
final Intent intent = getIntent(context);
|
||||
if (intent == null)
|
||||
{
|
||||
return false; // (if in release mode) don't do anything
|
||||
}
|
||||
|
||||
intent.putExtra(EXTRA_ERROR_REPORT_MSG, errorMessage);
|
||||
|
||||
createErrorFile(context);
|
||||
|
||||
try
|
||||
{
|
||||
startPendingErrorActivity(context, intent);
|
||||
}
|
||||
catch (CanceledException e)
|
||||
{
|
||||
Log.d("ErrorReport", "Couldn't send pending intent! Exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
killProcess(context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void killProcess(Context context)
|
||||
{
|
||||
// finish current activity and all below it first
|
||||
if (context instanceof Activity)
|
||||
{
|
||||
((Activity) context).finishAffinity();
|
||||
}
|
||||
|
||||
// kill process
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
}
|
||||
|
||||
static void startPendingErrorActivity(Context context, Intent intent) throws CanceledException
|
||||
{
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
pendingIntent.send(context, 0, intent);
|
||||
}
|
||||
|
||||
static String getErrorMessage(Throwable ex)
|
||||
{
|
||||
String content;
|
||||
PrintStream ps = null;
|
||||
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ps = new PrintStream(baos);
|
||||
ex.printStackTrace(ps);
|
||||
|
||||
try
|
||||
{
|
||||
content = baos.toString("US-ASCII");
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
content = e.getMessage();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ps != null)
|
||||
ps.close();
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
static Intent getIntent(Context context)
|
||||
{
|
||||
Class<?> errorActivityClass = Platform.getErrorActivityClass(); // can be null or can be provided beforehand
|
||||
|
||||
// if in debug and errorActivityClass is not provided use ErrorReportActivity class
|
||||
if (errorActivityClass == null && JsDebugger.isDebuggableApp(context))
|
||||
{
|
||||
errorActivityClass = ErrorReportActivity.class;
|
||||
}
|
||||
|
||||
// if not in debug mode should return null and use the errorActivityClass implementation provided
|
||||
if (errorActivityClass == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, errorActivityClass);
|
||||
|
||||
intent.putExtra(EXTRA_NATIVESCRIPT_ERROR_REPORT, EXTRA_ERROR_REPORT_VALUE);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
static boolean hasIntent(Intent intent)
|
||||
{
|
||||
int value = intent.getIntExtra(EXTRA_NATIVESCRIPT_ERROR_REPORT, 0);
|
||||
|
||||
return value == EXTRA_ERROR_REPORT_VALUE;
|
||||
}
|
||||
|
||||
void buildUI()
|
||||
{
|
||||
Context context = activity;
|
||||
Intent intent = activity.getIntent();
|
||||
final String msg = intent.getStringExtra(EXTRA_ERROR_REPORT_MSG);
|
||||
|
||||
// container
|
||||
LinearLayout layout = new LinearLayout(context);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
activity.setContentView(layout);
|
||||
|
||||
// header
|
||||
TextView txtHeader = new TextView(context);
|
||||
txtHeader.setText("Unhandled Exception");
|
||||
|
||||
// error + stacktrace
|
||||
TextView txtErrorMsg = new TextView(context);
|
||||
txtErrorMsg.setText(msg);
|
||||
txtErrorMsg.setHeight(1000);
|
||||
txtErrorMsg.setMovementMethod(new ScrollingMovementMethod());
|
||||
|
||||
// copy button
|
||||
Button copyToClipboard = new Button(context);
|
||||
copyToClipboard.setText("Copy to clipboard");
|
||||
copyToClipboard.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
|
||||
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("nsError", msg);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
}
|
||||
});
|
||||
|
||||
layout.addView(txtHeader);
|
||||
layout.addView(txtErrorMsg);
|
||||
layout.addView(copyToClipboard);
|
||||
}
|
||||
|
||||
private static void createErrorFile(final Context context)
|
||||
{
|
||||
try
|
||||
{
|
||||
File errFile = new File(context.getFilesDir(), ERROR_FILE_NAME);
|
||||
errFile.createNewFile();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.d("ErrorReport", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class ErrorReportActivity extends Activity
|
||||
{
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
new ErrorReport(this).buildUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
// the moment the error activity is not in the foreground we want to kill the process
|
||||
super.onPause();
|
||||
ErrorReport.killProcess(this);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@JavaScriptImplementation(javaScriptFile = "app/tns_modules/ui/frme/frame.js")
|
||||
public class FragmentClass extends android.app.Fragment implements com.tns.NativeScriptHashCodeProvider {
|
||||
|
||||
public FragmentClass()
|
||||
{
|
||||
com.tns.Platform.initInstance(this);
|
||||
}
|
||||
|
||||
public void onHiddenChanged(boolean hidden) {
|
||||
java.lang.Object[] params = new Object[1];
|
||||
params[0] = hidden;
|
||||
com.tns.Platform.callJSMethod(this, "onHiddenChanged", void.class, params);
|
||||
}
|
||||
|
||||
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
|
||||
java.lang.Object[] params = new Object[3];
|
||||
params[0] = transit;
|
||||
params[1] = enter;
|
||||
params[2] = nextAnim;
|
||||
return (Animator)com.tns.Platform.callJSMethod(this, "onCreateAnimator", Animator.class, params);
|
||||
|
||||
}
|
||||
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
java.lang.Object[] params = new Object[1];
|
||||
params[0] = savedInstanceState;
|
||||
com.tns.Platform.callJSMethod(this, "onCreate", void.class, params);
|
||||
}
|
||||
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
java.lang.Object[] params = new Object[3];
|
||||
params[0] = inflater;
|
||||
params[1] = container;
|
||||
params[2] = savedInstanceState;
|
||||
return (View)com.tns.Platform.callJSMethod(this, "onCreateView", View.class, params);
|
||||
|
||||
}
|
||||
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
java.lang.Object[] params = new Object[1];
|
||||
params[0] = outState;
|
||||
com.tns.Platform.callJSMethod(this, "onSaveInstanceState", void.class, params);
|
||||
}
|
||||
|
||||
public void onDestroyView() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onDestroyView", void.class, params);
|
||||
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onDestroy", void.class, params);
|
||||
|
||||
}
|
||||
public boolean equals__super(java.lang.Object other) {
|
||||
return super.equals(other);
|
||||
}
|
||||
public int hashCode__super() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
public final class LogcatLogger implements Logger
|
||||
{
|
||||
private final static String DEFAULT_LOG_TAG = "TNS.Java";
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
public LogcatLogger(boolean isEnabled, Context context)
|
||||
{
|
||||
this.enabled = isEnabled;
|
||||
|
||||
if (!isEnabled)
|
||||
{
|
||||
this.initLogging(context);
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public final void setEnabled(boolean isEnabled)
|
||||
{
|
||||
enabled = isEnabled;
|
||||
}
|
||||
|
||||
public final void write(String msg)
|
||||
{
|
||||
Log.d(DEFAULT_LOG_TAG, msg);
|
||||
}
|
||||
|
||||
public final void write(String tag, String msg)
|
||||
{
|
||||
Log.d(tag, msg);
|
||||
}
|
||||
|
||||
private void initLogging(Context context)
|
||||
{
|
||||
boolean isDebuggableApp = JsDebugger.isDebuggableApp(context);
|
||||
|
||||
if (isDebuggableApp)
|
||||
{
|
||||
String verboseLoggingProp = Util.readSystemProperty("nativescript.verbose.logging");
|
||||
|
||||
if (Util.isPositive(verboseLoggingProp))
|
||||
{
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
@JavaScriptImplementation(javaScriptFile = "app/tns_modules/ui/frme/frame.js")
|
||||
public class NativeScriptActivity extends android.app.Activity implements com.tns.NativeScriptHashCodeProvider {
|
||||
|
||||
public NativeScriptActivity()
|
||||
{
|
||||
com.tns.Platform.initInstance(this);
|
||||
}
|
||||
|
||||
protected void onCreate(android.os.Bundle savedInstanceState) {
|
||||
java.lang.Object[] params = new Object[1];
|
||||
params[0] = savedInstanceState;
|
||||
com.tns.Platform.callJSMethod(this, "onCreate", void.class, params);
|
||||
}
|
||||
|
||||
protected void onSaveInstanceState(android.os.Bundle outState) {
|
||||
java.lang.Object[] params = new Object[1];
|
||||
params[0] = outState;
|
||||
com.tns.Platform.callJSMethod(this, "onSaveInstanceState", void.class, params);
|
||||
}
|
||||
|
||||
protected void onStart() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onStart", void.class, params);
|
||||
}
|
||||
|
||||
protected void onStop() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onStop", void.class, params);
|
||||
}
|
||||
|
||||
protected void onDestroy() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onDestroy", void.class, params);
|
||||
|
||||
}
|
||||
|
||||
public void onBackPressed() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onBackPressed", void.class, params);
|
||||
}
|
||||
|
||||
protected void onActivityResult(int requestCode, int resultCode, android.content.Intent data) {
|
||||
java.lang.Object[] params = new Object[3];
|
||||
params[0] = requestCode;
|
||||
params[1] = resultCode;
|
||||
params[2] = data;
|
||||
com.tns.Platform.callJSMethod(this, "onActivityResult", void.class, params);
|
||||
}
|
||||
|
||||
public boolean equals__super(java.lang.Object other) {
|
||||
return super.equals(other);
|
||||
}
|
||||
public int hashCode__super() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
@JavaScriptImplementation(javaScriptFile = "app/tns_modules/application/application.js")
|
||||
public class NativeScriptApplication extends android.app.Application implements com.tns.NativeScriptHashCodeProvider {
|
||||
|
||||
private static NativeScriptApplication thiz;
|
||||
|
||||
public NativeScriptApplication()
|
||||
{
|
||||
thiz = this;
|
||||
}
|
||||
|
||||
protected void attachBaseContext(android.content.Context param_0) {
|
||||
super.attachBaseContext(param_0);
|
||||
|
||||
new RuntimeHelper(this).initRuntime();
|
||||
|
||||
Platform.initInstance(this);
|
||||
}
|
||||
|
||||
|
||||
public void onCreate() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onCreate", void.class, params);
|
||||
}
|
||||
|
||||
public void onLowMemory() {
|
||||
java.lang.Object[] params = null;
|
||||
com.tns.Platform.callJSMethod(this, "onLowMemory", void.class, params);
|
||||
}
|
||||
|
||||
public void onTrimMemory(int level) {
|
||||
java.lang.Object[] params = new Object[1];
|
||||
params[0] = level;
|
||||
com.tns.Platform.callJSMethod(this, "onTrimMemory", void.class, params);
|
||||
}
|
||||
|
||||
|
||||
public boolean equals__super(java.lang.Object other) {
|
||||
return super.equals(other);
|
||||
}
|
||||
public int hashCode__super() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
public static Application getInstance() {
|
||||
return thiz;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,424 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.LocalServerSocket;
|
||||
import android.net.LocalSocket;
|
||||
import android.util.Log;
|
||||
|
||||
public class NativeScriptSyncService
|
||||
{
|
||||
private static String SYNC_ROOT_SOURCE_DIR = "/data/local/tmp/";
|
||||
private static final String SYNC_SOURCE_DIR = "/sync/";
|
||||
private static final String FULL_SYNC_SOURCE_DIR = "/fullsync/";
|
||||
private static final String REMOVED_SYNC_SOURCE_DIR = "/removedsync/";
|
||||
|
||||
private static Logger logger;
|
||||
private final Context context;
|
||||
|
||||
private final String syncPath;
|
||||
private final String fullSyncPath;
|
||||
private final String removedSyncPath;
|
||||
private final File fullSyncDir;
|
||||
private final File syncDir;
|
||||
private final File removedSyncDir;
|
||||
|
||||
private LocalServerSocketThread localServerThread;
|
||||
private Thread localServerJavaThread;
|
||||
|
||||
public NativeScriptSyncService(Logger logger, Context context)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.context = context;
|
||||
|
||||
syncPath = SYNC_ROOT_SOURCE_DIR + context.getPackageName() + SYNC_SOURCE_DIR;
|
||||
fullSyncPath = SYNC_ROOT_SOURCE_DIR + context.getPackageName() + FULL_SYNC_SOURCE_DIR;
|
||||
removedSyncPath = SYNC_ROOT_SOURCE_DIR + context.getPackageName() + REMOVED_SYNC_SOURCE_DIR;
|
||||
fullSyncDir = new File(fullSyncPath);
|
||||
syncDir = new File(syncPath);
|
||||
removedSyncDir = new File(removedSyncPath);
|
||||
}
|
||||
|
||||
public void sync()
|
||||
{
|
||||
if (logger != null && logger.isEnabled())
|
||||
{
|
||||
logger.write("Sync is enabled:");
|
||||
logger.write("Sync path : " + syncPath);
|
||||
logger.write("Full sync path : " + fullSyncPath);
|
||||
logger.write("Removed files sync path: " + removedSyncPath);
|
||||
}
|
||||
|
||||
if (fullSyncDir.exists())
|
||||
{
|
||||
executeFullSync(context, fullSyncDir);
|
||||
deleteRecursive(fullSyncDir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (syncDir.exists())
|
||||
{
|
||||
executePartialSync(context, syncDir);
|
||||
deleteRecursive(syncDir);
|
||||
}
|
||||
|
||||
if (removedSyncDir.exists())
|
||||
{
|
||||
executeRemovedSync(context, removedSyncDir);
|
||||
deleteRecursive(removedSyncDir);
|
||||
}
|
||||
}
|
||||
|
||||
private class LocalServerSocketThread implements Runnable
|
||||
{
|
||||
private volatile boolean running;
|
||||
private final String name;
|
||||
|
||||
private ListenerWorker commThread;
|
||||
private LocalServerSocket serverSocket;
|
||||
|
||||
public LocalServerSocketThread(String name)
|
||||
{
|
||||
this.name = name;
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
this.running = false;
|
||||
try
|
||||
{
|
||||
serverSocket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
running = true;
|
||||
try
|
||||
{
|
||||
serverSocket = new LocalServerSocket(this.name);
|
||||
while (running)
|
||||
{
|
||||
LocalSocket socket = serverSocket.accept();
|
||||
commThread = new ListenerWorker(socket);
|
||||
new Thread(commThread).start();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ListenerWorker implements Runnable
|
||||
{
|
||||
private final DataInputStream input;
|
||||
private Closeable socket;
|
||||
private OutputStream output;
|
||||
|
||||
public ListenerWorker(LocalSocket socket) throws IOException
|
||||
{
|
||||
this.socket = socket;
|
||||
input = new DataInputStream(socket.getInputStream());
|
||||
output = socket.getOutputStream();
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
int length = input.readInt();
|
||||
input.readFully(new byte[length]); // ignore the payload
|
||||
executePartialSync(context, syncDir);
|
||||
executeRemovedSync(context, removedSyncDir);
|
||||
|
||||
Platform.runScript(new File(NativeScriptSyncService.this.context.getFilesDir(), "internal/livesync.js"));
|
||||
try
|
||||
{
|
||||
output.write(1);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startServer()
|
||||
{
|
||||
localServerThread = new LocalServerSocketThread(context.getPackageName() + "-livesync");
|
||||
localServerJavaThread = new Thread(localServerThread);
|
||||
localServerJavaThread.start();
|
||||
}
|
||||
|
||||
private void deleteRecursive(File fileOrDirectory)
|
||||
{
|
||||
|
||||
if (fileOrDirectory.isDirectory())
|
||||
{
|
||||
for (File child : fileOrDirectory.listFiles())
|
||||
{
|
||||
deleteRecursive(child);
|
||||
}
|
||||
}
|
||||
|
||||
fileOrDirectory.delete();
|
||||
}
|
||||
|
||||
public static boolean isSyncEnabled(Context context)
|
||||
{
|
||||
int flags;
|
||||
boolean shouldExecuteSync = false;
|
||||
try
|
||||
{
|
||||
flags = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).applicationInfo.flags;
|
||||
shouldExecuteSync = ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return shouldExecuteSync;
|
||||
}
|
||||
|
||||
final FileFilter deletingFilesFilter = new FileFilter()
|
||||
{
|
||||
@Override
|
||||
public boolean accept(File pathname)
|
||||
{
|
||||
if (pathname.isDirectory())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean success = pathname.delete();
|
||||
if (!success)
|
||||
{
|
||||
logger.write("Syncing: file not deleted: " + pathname.getAbsolutePath().toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private void deleteDir(File directory)
|
||||
{
|
||||
File[] subDirectories = directory.listFiles(deletingFilesFilter);
|
||||
if (subDirectories != null)
|
||||
{
|
||||
for (int i = 0; i < subDirectories.length; i++)
|
||||
{
|
||||
File subDir = subDirectories[i];
|
||||
deleteDir(subDir);
|
||||
}
|
||||
}
|
||||
|
||||
boolean success = directory.delete();
|
||||
if (!success && directory.exists())
|
||||
{
|
||||
logger.write("Syncing: directory not deleted: " + directory.getAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void moveFiles(File sourceDir, String sourceRootAbsolutePath, String targetRootAbsolutePath)
|
||||
{
|
||||
File[] files = sourceDir.listFiles();
|
||||
|
||||
if (files != null)
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Syncing total number of fiiles: " + files.length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < files.length; i++)
|
||||
{
|
||||
File file = files[i];
|
||||
if (file.isFile())
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Syncing: " + file.getAbsolutePath().toString());
|
||||
}
|
||||
|
||||
String targetFilePath = file.getAbsolutePath().replace(sourceRootAbsolutePath, targetRootAbsolutePath);
|
||||
File targetFileDir = new File(targetFilePath);
|
||||
|
||||
File targetParent = targetFileDir.getParentFile();
|
||||
if (targetParent != null)
|
||||
{
|
||||
targetParent.mkdirs();
|
||||
}
|
||||
|
||||
boolean success = copyFile(file.getAbsolutePath(), targetFilePath);
|
||||
if (!success)
|
||||
{
|
||||
logger.write("Sync failed: " + file.getAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
moveFiles(file, sourceRootAbsolutePath, targetRootAbsolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Can't move files. Source is empty.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this removes only the app directory from the device to preserve
|
||||
// any existing files in /files directory on the device
|
||||
private void executeFullSync(Context context, final File sourceDir)
|
||||
{
|
||||
String appPath = context.getFilesDir().getAbsolutePath() + "/app";
|
||||
final File appDir = new File(appPath);
|
||||
|
||||
if (appDir.exists())
|
||||
{
|
||||
deleteDir(appDir);
|
||||
moveFiles(sourceDir, sourceDir.getAbsolutePath(), appDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
private void executePartialSync(Context context, File sourceDir)
|
||||
{
|
||||
String appPath = context.getFilesDir().getAbsolutePath() + "/app";
|
||||
final File appDir = new File(appPath);
|
||||
|
||||
if (!appDir.exists())
|
||||
{
|
||||
Log.e("TNS", "Application dir does not exists. Partial Sync failed. appDir: " + appPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Syncing sourceDir " + sourceDir.getAbsolutePath() + " with " + appDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
moveFiles(sourceDir, sourceDir.getAbsolutePath(), appDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
private void deleteRemovedFiles(File sourceDir, String sourceRootAbsolutePath, String targetRootAbsolutePath)
|
||||
{
|
||||
if (!sourceDir.exists())
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Directory does not exist: " + sourceDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
File[] files = sourceDir.listFiles();
|
||||
|
||||
if (files != null)
|
||||
{
|
||||
for (int i = 0; i < files.length; i++)
|
||||
{
|
||||
File file = files[i];
|
||||
if (file.isFile())
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Syncing removed file: " + file.getAbsolutePath().toString());
|
||||
}
|
||||
|
||||
String targetFilePath = file.getAbsolutePath().replace(sourceRootAbsolutePath, targetRootAbsolutePath);
|
||||
File targetFile = new File(targetFilePath);
|
||||
targetFile.delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
deleteRemovedFiles(file, sourceRootAbsolutePath, targetRootAbsolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void executeRemovedSync(final Context context, final File sourceDir)
|
||||
{
|
||||
String appPath = context.getFilesDir().getAbsolutePath() + "/app";
|
||||
deleteRemovedFiles(sourceDir, sourceDir.getAbsolutePath(), appPath);
|
||||
}
|
||||
|
||||
private boolean copyFile(String sourceFile, String destinationFile)
|
||||
{
|
||||
FileInputStream fis = null;
|
||||
FileOutputStream fos = null;
|
||||
|
||||
try
|
||||
{
|
||||
fis = new FileInputStream(sourceFile);
|
||||
fos = new FileOutputStream(destinationFile, false);
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int read = 0;
|
||||
|
||||
while ((read = fis.read(buffer)) != -1)
|
||||
{
|
||||
fos.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
logger.write("Error copying file " + sourceFile);
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.write("Error copying file " + sourceFile);
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fis != null)
|
||||
{
|
||||
fis.close();
|
||||
}
|
||||
if (fos != null)
|
||||
{
|
||||
fos.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class NativeScriptUncaughtExceptionHandler implements UncaughtExceptionHandler
|
||||
{
|
||||
private final Context context;
|
||||
|
||||
private final UncaughtExceptionHandler defaultHandler;
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public NativeScriptUncaughtExceptionHandler(Logger logger, Context context)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.context = context;
|
||||
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable ex)
|
||||
{
|
||||
String errorMessage = ErrorReport.getErrorMessage(ex);
|
||||
|
||||
if (Platform.isInitialized())
|
||||
{
|
||||
try
|
||||
{
|
||||
ex.printStackTrace();
|
||||
Platform.passUncaughtExceptionToJsNative(ex, errorMessage);
|
||||
|
||||
if (JsDebugger.isJsDebugerActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("Uncaught Exception Message=" + errorMessage);
|
||||
}
|
||||
|
||||
if (!ErrorReport.startActivity(context, errorMessage) && defaultHandler != null)
|
||||
{
|
||||
defaultHandler.uncaughtException(thread, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
public class RuntimeHelper
|
||||
{
|
||||
private final Application app;
|
||||
|
||||
public RuntimeHelper(Application app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
// hasErrorIntent tells you if there was an event (with an uncaught exception) raised from ErrorReport
|
||||
public boolean hasErrorIntent()
|
||||
{
|
||||
boolean hasErrorIntent = false;
|
||||
|
||||
try
|
||||
{
|
||||
//empty file just to check if there was a raised uncaught error by ErrorReport
|
||||
File errFile = new File(app.getFilesDir(), ErrorReport.ERROR_FILE_NAME);
|
||||
|
||||
if (errFile.exists())
|
||||
{
|
||||
errFile.delete();
|
||||
hasErrorIntent = true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.d(logTag, e.getMessage());
|
||||
}
|
||||
|
||||
return hasErrorIntent;
|
||||
}
|
||||
|
||||
public void initRuntime()
|
||||
{
|
||||
System.loadLibrary("NativeScript");
|
||||
|
||||
Logger logger = new LogcatLogger(false, app);
|
||||
|
||||
boolean showErrorIntent = hasErrorIntent();
|
||||
if (!showErrorIntent)
|
||||
{
|
||||
Thread.UncaughtExceptionHandler exHandler = new NativeScriptUncaughtExceptionHandler(logger, app);
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler(exHandler);
|
||||
|
||||
Async.Http.setApplicationContext(this.app);
|
||||
|
||||
ExtractPolicy extractPolicy = new DefaultExtractPolicy(logger);
|
||||
boolean skipAssetExtraction = Util.runPlugin(logger, app);
|
||||
if (!skipAssetExtraction)
|
||||
{
|
||||
new AssetExtractor(null, logger).extractAssets(app, extractPolicy);
|
||||
}
|
||||
|
||||
if (NativeScriptSyncService.isSyncEnabled(this.app))
|
||||
{
|
||||
NativeScriptSyncService syncService = new NativeScriptSyncService(logger, this.app);
|
||||
|
||||
syncService.sync();
|
||||
syncService.startServer();
|
||||
|
||||
// preserve this instance as strong reference
|
||||
// do not preserve in NativeScriptApplication field inorder to make the code more portable
|
||||
Platform.getOrCreateJavaObjectID(syncService);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
{
|
||||
logger.write("NativeScript LiveSync is not enabled.");
|
||||
}
|
||||
}
|
||||
String appName = app.getPackageName();
|
||||
File rootDir = new File(app.getApplicationInfo().dataDir);
|
||||
File appDir = app.getFilesDir();
|
||||
|
||||
ClassLoader classLoader = app.getClassLoader();
|
||||
File dexDir = new File(rootDir, "code_cache/secondary-dexes");
|
||||
String dexThumb = null;
|
||||
try
|
||||
{
|
||||
dexThumb = Util.getDexThumb(app);
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
if (logger.isEnabled()) logger.write("Error while getting current proxy thumb");
|
||||
e.printStackTrace();
|
||||
}
|
||||
ThreadScheduler workThreadScheduler = new WorkThreadScheduler(new Handler(Looper.getMainLooper()));
|
||||
Platform.init(this.app, workThreadScheduler, logger, appName, null, rootDir, appDir, classLoader, dexDir, dexThumb);
|
||||
Platform.runScript(new File(appDir, "internal/ts_helpers.js"));
|
||||
Platform.run();
|
||||
}
|
||||
}
|
||||
|
||||
private final String logTag = "MyApp";
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package com.tns;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import com.tns.internal.Plugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Bundle;
|
||||
|
||||
public final class Util
|
||||
{
|
||||
private Util()
|
||||
{
|
||||
}
|
||||
|
||||
public static String getDexThumb(Context context) throws NameNotFoundException
|
||||
{
|
||||
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
int code = packageInfo.versionCode;
|
||||
long updateTime = packageInfo.lastUpdateTime;
|
||||
return String.valueOf(updateTime) + "-" + String.valueOf(code);
|
||||
}
|
||||
|
||||
public static boolean isDebuggableApp(Context context)
|
||||
{
|
||||
int flags;
|
||||
try
|
||||
{
|
||||
flags = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).applicationInfo.flags;
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
flags = 0;
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
boolean isDebuggableApp = ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
|
||||
return isDebuggableApp;
|
||||
}
|
||||
|
||||
static boolean runPlugin(Logger logger, Context context)
|
||||
{
|
||||
boolean success = false;
|
||||
String pluginClassName = "org.nativescript.livesync.LiveSyncPlugin";
|
||||
try
|
||||
{
|
||||
ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
|
||||
Bundle metadataBundle = ai.metaData;
|
||||
if (metadataBundle != null)
|
||||
{
|
||||
pluginClassName = metadataBundle.getString("com.tns.internal.Plugin");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Class<?> liveSyncPluginClass = Class.forName(pluginClassName);
|
||||
Plugin p = (Plugin) liveSyncPluginClass.newInstance();
|
||||
success = p.execute(context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logger.isEnabled())
|
||||
e.printStackTrace();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public static String readSystemProperty(String name)
|
||||
{
|
||||
InputStreamReader in = null;
|
||||
BufferedReader reader = null;
|
||||
try
|
||||
{
|
||||
Process proc = Runtime.getRuntime().exec(new String[] { "/system/bin/getprop", name });
|
||||
in = new InputStreamReader(proc.getInputStream());
|
||||
reader = new BufferedReader(in);
|
||||
return reader.readLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
silentClose(in);
|
||||
silentClose(reader);
|
||||
}
|
||||
}
|
||||
|
||||
private static void silentClose(Closeable closeable)
|
||||
{
|
||||
if (closeable == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
closeable.close();
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean isPositive(String value)
|
||||
{
|
||||
return (value.equals("true") || value.equals("TRUE") ||
|
||||
value.equals("yes") || value.equals("YES") ||
|
||||
value.equals("enabled") || value.equals("ENABLED"));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.tns.internal;
|
||||
|
||||
import com.tns.ExtractPolicy;
|
||||
|
||||
public interface AppBuilderCallback
|
||||
{
|
||||
void onConfigurationChanged(android.content.Context context, android.content.res.Configuration newConfig);
|
||||
|
||||
void onCreate(android.content.Context context);
|
||||
|
||||
void onLowMemory(android.content.Context context);
|
||||
|
||||
void onTerminate(android.content.Context context);
|
||||
|
||||
void onTrimMemory(android.content.Context context, int level);
|
||||
|
||||
Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler();
|
||||
|
||||
ExtractPolicy getExtractPolicy();
|
||||
|
||||
boolean shouldEnableDebugging(android.content.Context context);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.tns.internal;
|
||||
|
||||
public interface Plugin
|
||||
{
|
||||
boolean execute(android.content.Context context) throws Exception;
|
||||
}
|
||||
Reference in New Issue
Block a user