Initial commit

This commit is contained in:
Victor 2013-07-11 13:28:06 +03:00
commit 291374b6e8
30 changed files with 949 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*.iml
*.iws
*.ipr
.idea/
.gradle/
local.properties
*/build/
*~
*.swp

View File

@ -0,0 +1,23 @@
buildscript {
repositories {
maven { url 'http://repo1.maven.org/maven2' }
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4'
}
}
apply plugin: 'android'
dependencies {
compile files('libs/android-support-v4.jar')
}
android {
compileSdkVersion 17
buildToolsVersion "17.0.0"
defaultConfig {
minSdkVersion 7
targetSdkVersion 17
}
}

Binary file not shown.

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.annimon.socketfiletransfer"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.annimon.socketfiletransfer.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="file/*" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name="com.annimon.socketfiletransfer.MessagesActivity"
android:label="@string/title_activity_messages" >
</activity>
<activity
android:name="com.annimon.socketfiletransfer.CursorActivity"
android:label="@string/title_activity_cursor" >
</activity>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,31 @@
package com.annimon.socketfiletransfer;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
/**
*
* @author aNNiMON
*/
public class CursorActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set fullscreen mode.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Set backlight always on.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
TouchpadView view = new TouchpadView(this);
view.requestFocus();
setContentView(view);
new SocketTransferTask(OperationListener.MODE_CURSOR_CONTROL).execute(view);
}
}

View File

@ -0,0 +1,138 @@
package com.annimon.socketfiletransfer;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.Toast;
import java.io.File;
public class MainActivity extends Activity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We don't need to show UI if sharing data.
if (checkSharingData()) {
finish();
}
LayoutParams layoutParam = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setLayoutParams(layoutParam);
// Create main menu
String[] items = getResources().getStringArray(R.array.main_menu);
for (int i = 0; i < items.length; i++) {
String item = items[i];
Button button = new Button(this);
button.setLayoutParams(layoutParam);
button.setTag(i);
button.setText(item);
button.setOnClickListener(this);
layout.addView(button);
}
setContentView(layout);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View view) {
final int id = (Integer) view.getTag();
switch (id) {
case OperationListener.MODE_SERVER:
break;
case OperationListener.MODE_FILE_TRANSFER:
onFileTransfer();
break;
case OperationListener.MODE_MESSAGE_TRANSFER:
Intent msgIntent = new Intent(this, MessagesActivity.class);
startActivity(msgIntent);
break;
case OperationListener.MODE_CURSOR_CONTROL:
Intent curIntent = new Intent(this, CursorActivity.class);
startActivity(curIntent);
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) return;
if (requestCode == OperationListener.MODE_FILE_TRANSFER) {
sendFile(data.getData());
}
}
private void sendFile(Uri uri) {
if (uri == null) return;
String path = uri.getPath();
if (uri.getScheme().startsWith("content")) path = getRealPathFromURI(uri);
File file = new File(path);
new SocketTransferTask(OperationListener.MODE_FILE_TRANSFER).execute(file);
}
private String getRealPathFromURI(Uri contentUri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(contentUri, projection, null, null, null);
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(columnIndex);
}
private void onFileTransfer() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
try {
startActivityForResult(intent, OperationListener.MODE_FILE_TRANSFER);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, getString(R.string.app_not_found), Toast.LENGTH_SHORT).show();
}
}
private boolean checkSharingData() {
Intent intent = getIntent();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(intent.getAction()) && type != null) {
if (type.startsWith("file/") || type.startsWith("image/")) {
Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
sendFile(uri);
return true;
} else if ("text/plain".equals(type)) {
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
new SocketTransferTask(OperationListener.MODE_MESSAGE_TRANSFER).execute(text);
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,37 @@
package com.annimon.socketfiletransfer;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import com.annimon.socketfiletransfer.util.MessageHistory;
public class MessagesActivity extends Activity implements View.OnClickListener {
private EditText editText;
private TextView messagesHistory;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
findViewById(R.id.send_text_button).setOnClickListener(this);
editText = (EditText) findViewById(R.id.message_edit_text);
messagesHistory = (TextView) findViewById(R.id.messages_history);
messagesHistory.setText(MessageHistory.getAllText());
}
@Override
public void onClick(View view) {
String text = editText.getText().toString();
new SocketTransferTask(OperationListener.MODE_MESSAGE_TRANSFER).execute(text);
editText.setText("");
MessageHistory.addMessage(" >> " + text);
messagesHistory.setText(MessageHistory.getAllText());
}
}

View File

@ -0,0 +1,73 @@
package com.annimon.socketfiletransfer;
import com.annimon.socketfiletransfer.operations.MessageOperation;
import com.annimon.socketfiletransfer.operations.FileOperation;
import com.annimon.socketfiletransfer.operations.Operation;
import com.annimon.socketfiletransfer.util.ExceptionHandler;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
/**
* Прослушивание операций с данными.
* @author aNNiMON
*/
public class OperationListener {
public static final int
MODE_SERVER = 0,
MODE_FILE_TRANSFER = 1,
MODE_MESSAGE_TRANSFER = 2,
MODE_CURSOR_CONTROL = 3;
protected DataInputStream dis;
protected DataOutputStream dos;
public void setSocket(Socket socket) {
try {
dis = new DataInputStream( socket.getInputStream() );
dos = new DataOutputStream( socket.getOutputStream() );
} catch (IOException ex) {
ExceptionHandler.log(ex);
}
}
public void listenOperation() throws Exception {
int mode = dis.readInt();
Operation operation;
switch(mode) {
case MODE_FILE_TRANSFER:
operation = new FileOperation(dis);
break;
case MODE_MESSAGE_TRANSFER:
operation = new MessageOperation(dis);
break;
// case MODE_CURSOR_CONTROL:
// operation = new CursorOperation(dis);
// break;
default:
return;
}
if (operation != null) {
operation.startServerSide();
}
}
public void close() {
if (dis != null) {
try {
dis.close();
} catch (IOException ex) {
ExceptionHandler.log(ex);
}
}
if (dos != null) {
try {
dos.close();
} catch (IOException ex) {
ExceptionHandler.log(ex);
}
}
}
}

View File

@ -0,0 +1,32 @@
package com.annimon.socketfiletransfer;
import com.annimon.socketfiletransfer.operations.CursorOperation;
import com.annimon.socketfiletransfer.operations.FileOperation;
import com.annimon.socketfiletransfer.operations.MessageOperation;
import com.annimon.socketfiletransfer.operations.Operation;
/**
* Manage data operations.
* @author aNNiMON
*/
public class OperationManager extends OperationListener {
public void execute(int mode, Object... params) throws Exception {
Operation operation = null;
switch (mode) {
case MODE_FILE_TRANSFER:
operation = new FileOperation(dos);
break;
case MODE_MESSAGE_TRANSFER:
operation = new MessageOperation(dos);
break;
case MODE_CURSOR_CONTROL:
operation = new CursorOperation(dos);
break;
}
if (operation != null) {
operation.startClientSide(params);
}
}
}

View File

@ -0,0 +1,40 @@
package com.annimon.socketfiletransfer;
import android.os.AsyncTask;
import android.util.Log;
import java.net.Socket;
public class SocketTransferTask extends AsyncTask<Object, Void, Boolean> {
/** Transfer mode */
private int mode;
public SocketTransferTask(int mode) {
this.mode = mode;
}
@Override
protected Boolean doInBackground(Object... objects) {
boolean success = true;
OperationManager manager = new OperationManager();
try {
Socket socket = new Socket("192.168.1.35", 7119);
manager.setSocket(socket);
manager.execute(mode, objects);
} catch (Exception e) {
success = false;
e.printStackTrace();
Log.e("SFT", e.getMessage(), e);
} finally {
if (manager != null) manager.close();
}
return success;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
}
}

View File

@ -0,0 +1,43 @@
package com.annimon.socketfiletransfer;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
/**
* @author aNNiMON
*/
public class TouchpadView extends View {
public TouchpadView(Context context) {
super(context);
initView();
}
public TouchpadView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public TouchpadView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView() {
setFocusable(true);
setFocusableInTouchMode(true);
}
public void closeActivity() {
((Activity)getContext()).finish();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.GRAY);
}
}

View File

@ -0,0 +1,149 @@
package com.annimon.socketfiletransfer.operations;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import com.annimon.socketfiletransfer.OperationListener;
import com.annimon.socketfiletransfer.TouchpadView;
import com.annimon.socketfiletransfer.util.ExceptionHandler;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* @author aNNiMON
*/
public class CursorOperation implements Operation {
private static final int
NONE = -1,
TYPE_MOVE = 1,
TYPE_CLICK = 2,
TYPE_DRAG = 3,
TYPE_RELEASED = 4,
TYPE_KEY_RELEASED = 5,
STOP = 10;
private DataInputStream dis;
private DataOutputStream dos;
private boolean running;
public CursorOperation(DataInputStream dis) {
this.dis = dis;
}
public CursorOperation(DataOutputStream dos) {
this.dos = dos;
}
@Override
public void startServerSide() throws Exception {
}
@Override
public void startClientSide(Object... params) throws Exception {
TouchpadView view = (TouchpadView) params[0];
running = true;
dos.writeInt(OperationListener.MODE_CURSOR_CONTROL);
// Send view size
dos.writeInt(view.getWidth());
dos.writeInt(view.getHeight());
view.requestFocus();
view.setOnTouchListener(touchListener);
view.setOnKeyListener(keyListener);
while(running) {
Thread.sleep(10);
}
view.closeActivity();
}
private View.OnTouchListener touchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (!running) return true;
int x = (int) motionEvent.getX();
int y = (int) motionEvent.getY();
int action = motionEvent.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN) {
try {
dos.writeInt(TYPE_MOVE);
dos.writeInt(x);
dos.writeInt(y);
} catch (IOException ex) { }
// Click event
if (motionEvent.getPointerCount() > 1) {
try {
dos.writeInt(TYPE_CLICK);
int mask = motionEvent.getPointerCount() - 2;
dos.writeInt(16 >> mask);
} catch (IOException ex) { }
}
} else if ( (action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL) ) {
try {
dos.writeInt(TYPE_RELEASED);
} catch (IOException ex) { }
} else if (action == MotionEvent.ACTION_MOVE) {
try {
dos.writeInt(TYPE_DRAG);
dos.writeInt(x);
dos.writeInt(y);
} catch (IOException ex) { }
}
return true;
}
};
private View.OnKeyListener keyListener = new View.OnKeyListener() {
@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (!running) return true;
if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
try {
dos.writeInt(TYPE_KEY_RELEASED);
dos.writeInt(convertToAscii(keyCode));
} catch (IOException e) {
ExceptionHandler.log(e);
}
if (keyCode == KeyEvent.KEYCODE_BACK) {
running = false;
}
}
return true;
}
private int convertToAscii(int key) {
if (key >= KeyEvent.KEYCODE_A && key <= KeyEvent.KEYCODE_Z)
return key - KeyEvent.KEYCODE_A + 'A';
else if (key >= KeyEvent.KEYCODE_0 && key <= KeyEvent.KEYCODE_9)
return key - KeyEvent.KEYCODE_0 + '0';
else if (key == KeyEvent.KEYCODE_ENTER) return 10;
else if (key == KeyEvent.KEYCODE_SHIFT_LEFT ||
key == KeyEvent.KEYCODE_SHIFT_RIGHT) return 0x16;
else if (key == KeyEvent.KEYCODE_SPACE) return 32;
else if (key == KeyEvent.KEYCODE_DEL) return 8; // Backspace
else if (key == KeyEvent.KEYCODE_MENU) return 525; // Context Menu
else if (key == KeyEvent.KEYCODE_VOLUME_UP) return 33; // Page up
else if (key == KeyEvent.KEYCODE_VOLUME_DOWN) return 34; // Page down
else if (key == KeyEvent.KEYCODE_DPAD_LEFT) return 37;
else if (key == KeyEvent.KEYCODE_DPAD_UP) return 38;
else if (key == KeyEvent.KEYCODE_DPAD_RIGHT) return 39;
else if (key == KeyEvent.KEYCODE_DPAD_DOWN) return 40;
else return key;
}
};
}

View File

@ -0,0 +1,78 @@
package com.annimon.socketfiletransfer.operations;
import com.annimon.socketfiletransfer.MainActivity;
import com.annimon.socketfiletransfer.OperationListener;
import com.annimon.socketfiletransfer.OperationManager;
import com.annimon.socketfiletransfer.util.ExceptionHandler;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
*
* @author aNNiMON
*/
public class FileOperation implements Operation {
private static final int BUFFER_SIZE = 1024;
private DataInputStream dis;
private DataOutputStream dos;
public FileOperation(DataInputStream dis) {
this.dis = dis;
}
public FileOperation(DataOutputStream dos) {
this.dos = dos;
}
@Override
public void startServerSide() {
FileOutputStream fout = null;
try {
String name = dis.readUTF();
fout = new FileOutputStream("/mnt/sdcard/" + name);//Config.getTransferDir() + name);
byte[] buffer = new byte[BUFFER_SIZE];
int count;
while ((count = dis.read(buffer, 0, BUFFER_SIZE)) != -1) {
fout.write(buffer, 0, count);
}
fout.flush();
fout.close();
} catch (IOException ex) {
ExceptionHandler.log(ex);
} finally {
try {
fout.close();
} catch (IOException ex) {
ExceptionHandler.log(ex);
}
}
}
@Override
public void startClientSide(Object... params) throws Exception {
File file = (File) params[0];
dos.writeInt(OperationListener.MODE_FILE_TRANSFER);
String name = file.getName();
dos.writeUTF(name);
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[BUFFER_SIZE];
int count;
while ((count = fis.read(buffer, 0, BUFFER_SIZE)) != -1) {
dos.write(buffer, 0, count);
}
dos.flush();
fis.close();
}
}

View File

@ -0,0 +1,42 @@
package com.annimon.socketfiletransfer.operations;
import android.util.Log;
import com.annimon.socketfiletransfer.OperationListener;
import com.annimon.socketfiletransfer.util.MessageHistory;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
*
* @author aNNiMON
*/
public class MessageOperation implements Operation {
private DataInputStream dis;
private DataOutputStream dos;
public MessageOperation(DataInputStream dis) {
this.dis = dis;
}
public MessageOperation(DataOutputStream dos) {
this.dos = dos;
}
@Override
public void startServerSide() throws IOException {
String text = dis.readUTF();
MessageHistory.addMessage(text);
}
@Override
public void startClientSide(Object... params) throws Exception {
String message = (String) params[0];
dos.writeInt(OperationListener.MODE_MESSAGE_TRANSFER);
dos.writeUTF(message);
}
}

View File

@ -0,0 +1,13 @@
package com.annimon.socketfiletransfer.operations;
/**
*
* @author aNNiMON
*/
public interface Operation {
void startServerSide() throws Exception;
void startClientSide(Object... params) throws Exception;
}

View File

@ -0,0 +1,61 @@
package com.annimon.socketfiletransfer.util;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
/**
* Handling exceptions.
* If error is critical or must be show to user, then
* call <b>alert</b> method.
* In other situations call <b>log</b> method.
*
* @author aNNiMON
*/
public class ExceptionHandler {
private static final boolean DEBUG = false;
private static final String TAG = "ExceptionHandler";
public static void alert(Context context, Exception ex) {
alert(context, getErrorMessage(ex));
}
public static void alert(Context context, int resourceId) {
alert(context, context.getString(resourceId));
}
public static void alert(Context context, String message) {
new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(android.R.string.dialog_alert_title)
.setMessage(message)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
}
public static void log(Exception ex) {
if (DEBUG) {
Log.e(TAG, getErrorMessage(ex));
}
}
public static void log(String message) {
if (DEBUG) {
Log.e(TAG, message);
}
}
private static String getErrorMessage(Exception ex) {
return ex.getMessage();
}
}

View File

@ -0,0 +1,25 @@
package com.annimon.socketfiletransfer.util;
/**
*
* @author aNNiMON
*/
public class MessageHistory {
private static String lastMessage = "";
private static StringBuilder allText = new StringBuilder();
public static void addMessage(String message) {
lastMessage = message;
allText.append(message).append("\r\n\r\n");
}
public static String getLastMessage() {
return lastMessage;
}
public static String getAllText() {
return allText.toString();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -0,0 +1,29 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MessagesActivity">
<EditText android:id="@+id/message_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button android:id="@+id/send_text_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/send" />
<ScrollView android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/messages_history"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
android:showAsAction="never" />
</menu>

View File

@ -0,0 +1,4 @@
<resources>
<!-- Customize dimensions originally defined in res/values/dimens.xml (such as
screen margins) for sw600dp devices (e.g. 7" tablets) here. -->
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<!-- Customize dimensions originally defined in res/values/dimens.xml (such as
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
<dimen name="activity_horizontal_margin">128dp</dimen>
</resources>

View File

@ -0,0 +1,11 @@
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">SocketFileTransfer</string>
<string name="action_settings">Settings</string>
<string name="send_message">Send message</string>
<string name="app_not_found">Application not found</string>
<string name="title_activity_messages">Messages</string>
<string name="title_activity_cursor">Cursor control</string>
<string name="send">Send</string>
<string-array name="main_menu">
<item>Start server</item>
<item>File transfer</item>
<item>Send message</item>
<item>Cursor control</item>
</string-array>
</resources>

View File

@ -0,0 +1,20 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>