Added rotation of presentation view.
Change-Id: Iea68b7740c5e7cf9380c91b8b85ff02fd9c11b8e
Before Width: | Height: | Size: 222 B After Width: | Height: | Size: 203 B |
BIN
android/sdremote/res/drawable-hdpi/handle_vertical_default.9.png
Normal file
After Width: | Height: | Size: 263 B |
BIN
android/sdremote/res/drawable-hdpi/handle_vertical_light.9.png
Normal file
After Width: | Height: | Size: 202 B |
9
android/sdremote/res/drawable-land/handle.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/handle_vertical_light" android:state_activated="true"/>
|
||||
<item android:drawable="@drawable/handle_vertical_light" android:state_pressed="true"/>
|
||||
<item android:drawable="@drawable/handle_vertical_light" android:state_focused="true"/>
|
||||
<item android:drawable="@drawable/handle_vertical_default"/>
|
||||
|
||||
</selector>
|
BIN
android/sdremote/res/drawable-mdpi/handle_vertical_default.9.png
Normal file
After Width: | Height: | Size: 263 B |
BIN
android/sdremote/res/drawable-mdpi/handle_vertical_light.9.png
Normal file
After Width: | Height: | Size: 202 B |
After Width: | Height: | Size: 263 B |
BIN
android/sdremote/res/drawable-xhdpi/handle_vertical_light.9.png
Normal file
After Width: | Height: | Size: 202 B |
54
android/sdremote/res/layout-land/fragment_presentation.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/presentation_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<pl.polidea.coverflow.CoverFlow
|
||||
xmlns:coverflow="http://schemas.android.com/apk/res/org.libreoffice.impressremote"
|
||||
android:id="@+id/presentation_coverflow"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dip"
|
||||
coverflow:imageHeight="150dip"
|
||||
coverflow:imageWidth="180dip"
|
||||
coverflow:withReflection="false" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/presentation_slidenumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/presentation_handle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginRight="6dp"
|
||||
android:contentDescription="@string/presentation_ui_resizehandle"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/handle" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/presentation_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<WebView
|
||||
android:id="@+id/presentation_notes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
@@ -5,24 +5,29 @@
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:id="@+id/pairing_instruction1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="10dip"
|
||||
android:gravity="center"
|
||||
android:text="@string/pairing_instructions_1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:id="@+id/pairing_instruction2_deviceName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/pairing_instructions_2" />
|
||||
android:layout_margin="10dip"
|
||||
android:gravity="center"
|
||||
android:text="@string/pairing_instructions_2_deviceName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView3"
|
||||
android:id="@+id/pairing_instruction3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="10dip"
|
||||
android:text="@string/pairing_instructions_3" />
|
||||
|
||||
<TextView
|
||||
@@ -30,7 +35,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="10dip"
|
||||
android:text=""
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="75dip" />
|
||||
|
||||
</LinearLayout>
|
@@ -24,7 +24,7 @@
|
||||
<string name="wifi">WI-FI</string>
|
||||
<string name="selector_noservers">Searching for computers…</string>
|
||||
<string name="pairing_instructions_1">In Impress, click on the "Slideshow" menu and select "Impress Remote".</string>
|
||||
<string name="pairing_instructions_2">Choose "{1}" as your device.</string>
|
||||
<string name="pairing_instructions_2_deviceName">Choose "{1}" as your device.</string>
|
||||
<string name="pairing_instructions_3">Then input this PIN:</string>
|
||||
|
||||
</resources>
|
@@ -8,26 +8,36 @@
|
||||
*/
|
||||
package org.libreoffice.impressremote;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.libreoffice.impressremote.communication.CommunicationService;
|
||||
import org.libreoffice.impressremote.communication.CommunicationService.State;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class PairingActivity extends Activity {
|
||||
|
||||
private CommunicationService mCommunicationService;
|
||||
private boolean mIsBound = false;
|
||||
private TextView mPinText;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_pairing);
|
||||
|
||||
bindService(new Intent(this, CommunicationService.class), mConnection,
|
||||
Context.BIND_IMPORTANT);
|
||||
mIsBound = true;
|
||||
|
||||
mPinText = (TextView) findViewById(R.id.pairing_pin);
|
||||
|
||||
@@ -46,6 +56,33 @@ public class PairingActivity extends Activity {
|
||||
// refreshLists();
|
||||
}
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName aClassName,
|
||||
IBinder aService) {
|
||||
setContentView(R.layout.activity_pairing);
|
||||
|
||||
((TextView) findViewById(R.id.pairing_instruction2_deviceName))
|
||||
.setText(MessageFormat
|
||||
.format(getResources()
|
||||
.getString(R.string.pairing_instructions_2_deviceName),
|
||||
mCommunicationService
|
||||
.getDeviceName()));
|
||||
|
||||
mCommunicationService = ((CommunicationService.CBinder) aService)
|
||||
.getService();
|
||||
if (mCommunicationService.getState() == State.CONNECTING) {
|
||||
mPinText.setText(mCommunicationService.getPairingPin());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName aClassName) {
|
||||
mCommunicationService = null;
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mListener = new BroadcastReceiver() {
|
||||
|
||||
@Override
|
||||
|
@@ -7,6 +7,7 @@ import pl.polidea.coverflow.AbstractCoverFlowImageAdapter;
|
||||
import pl.polidea.coverflow.CoverFlow;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
@@ -57,9 +58,6 @@ public class PresentationFragment extends Fragment {
|
||||
mNotes.loadData(summary, "text/html", null);
|
||||
mNotes.setBackgroundColor(Color.TRANSPARENT);
|
||||
|
||||
// TextView aText = new TextView();
|
||||
// aText.setText
|
||||
|
||||
mTopView = (CoverFlow) v.findViewById(R.id.presentation_coverflow);
|
||||
|
||||
mLayout = v.findViewById(R.id.presentation_layout);
|
||||
@@ -111,17 +109,20 @@ public class PresentationFragment extends Fragment {
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
LayoutParams aParams = mTopView.getLayoutParams();
|
||||
int aHeight = mTopView.getHeight();
|
||||
int aViewSize = mLayout.getHeight();
|
||||
|
||||
final int DRAG_MARGIN = 120;
|
||||
|
||||
boolean aPortrait = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
|
||||
|
||||
int aFlowSize = mTopView.getHeight();
|
||||
int aViewSize = mLayout.getHeight();
|
||||
|
||||
// Calculate height change, taking limits into account
|
||||
int aDiff = (int) (aEvent.getY());
|
||||
if (aDiff + aHeight < DRAG_MARGIN) {
|
||||
aDiff = DRAG_MARGIN - aHeight;
|
||||
} else if ((aHeight + aDiff) > (aViewSize - DRAG_MARGIN)) {
|
||||
aDiff = (aViewSize - DRAG_MARGIN) - aHeight;
|
||||
int aDiff = (int) (aPortrait ? aEvent.getY() : aEvent.getX());
|
||||
if (aDiff + aFlowSize < DRAG_MARGIN) {
|
||||
aDiff = DRAG_MARGIN - aFlowSize;
|
||||
} else if ((aFlowSize + aDiff) > (aViewSize - DRAG_MARGIN)) {
|
||||
aDiff = (aViewSize - DRAG_MARGIN) - aFlowSize;
|
||||
}
|
||||
|
||||
// Now deal with the internal height
|
||||
@@ -130,15 +131,27 @@ public class PresentationFragment extends Fragment {
|
||||
|
||||
double aRatio = mOriginalCoverflowWidth
|
||||
/ mOriginalCoverflowHeight;
|
||||
float aHeightNew = mTopView.getImageHeight() + aDiff;
|
||||
float aWidthNew = (float) (aRatio * aHeightNew);
|
||||
|
||||
float aHeightNew;
|
||||
float aWidthNew;
|
||||
if (aPortrait) {
|
||||
aHeightNew = mTopView.getImageHeight() + aDiff;
|
||||
aWidthNew = (float) (aRatio * aHeightNew);
|
||||
// Too wide -- so scale down
|
||||
if (aWidthNew > mLayout.getWidth() - 50) {
|
||||
aWidthNew = mLayout.getWidth() - 50;
|
||||
aHeightNew = (float) (aWidthNew / aRatio);
|
||||
aDiff = (int) (aHeightNew - mTopView.getImageHeight());
|
||||
}
|
||||
} else {
|
||||
aWidthNew = mTopView.getImageWidth();
|
||||
aHeightNew = (float) (aWidthNew / aRatio);
|
||||
// Too High -- so scale down
|
||||
if (aHeightNew > mLayout.getHeight() - 50) {
|
||||
aHeightNew = mLayout.getHeight() - 50;
|
||||
aWidthNew = (float) (aHeightNew / aRatio);
|
||||
aDiff = (int) (aWidthNew - mTopView.getImageWidth());
|
||||
}
|
||||
}
|
||||
|
||||
mNewCoverflowHeight = aHeightNew;
|
||||
mNewCoverflowWidth = aWidthNew;
|
||||
|
@@ -158,9 +158,9 @@ public class SelectorActivity extends Activity {
|
||||
aLayout);
|
||||
TextView aText = (TextView) aView
|
||||
.findViewById(R.id.selector_sub_label);
|
||||
aView.setOnClickListener(mClickListener);
|
||||
aText.setOnClickListener(mClickListener);
|
||||
aText.setText(aServer.getName());
|
||||
aMap.put(aServer, aView);
|
||||
aMap.put(aServer, aText);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -182,7 +182,6 @@ public class SelectorActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onClick(View aView) {
|
||||
// TODO Auto-generated method stub
|
||||
mCommunicationService.stopFindingServers();
|
||||
|
||||
Server aDesiredServer = null;
|
||||
|
@@ -32,6 +32,7 @@ public abstract class Client {
|
||||
protected InputStream mInputStream;
|
||||
protected BufferedReader mReader;
|
||||
protected OutputStream mOutputStream;
|
||||
protected String mPin = "";
|
||||
|
||||
public abstract void closeConnection();
|
||||
|
||||
@@ -79,6 +80,10 @@ public abstract class Client {
|
||||
|
||||
}
|
||||
|
||||
public String getPin() {
|
||||
return mPin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a valid JSON string to the server.
|
||||
*
|
||||
|
@@ -27,6 +27,22 @@ public class CommunicationService extends Service implements Runnable {
|
||||
|
||||
private State mState = State.DISCONNECTED;
|
||||
|
||||
public State getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
public String getPairingPin() {
|
||||
if (mClient != null)
|
||||
return mClient.getPin();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return "Bob";
|
||||
// FIXME: get the device name somehow.
|
||||
}
|
||||
|
||||
private State mStateDesired = State.DISCONNECTED;
|
||||
|
||||
private Server mServerDesired = null;
|
||||
|
@@ -17,7 +17,6 @@ import java.util.Random;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.StrictMode;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
/**
|
||||
@@ -33,10 +32,6 @@ public class NetworkClient extends Client {
|
||||
|
||||
public NetworkClient(String ipAddress, Context aContext) {
|
||||
super(aContext);
|
||||
// FIXME: eventually networking will be fully threaded.
|
||||
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
|
||||
.permitAll().build();
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
try {
|
||||
mSocket = new Socket(ipAddress, PORT);
|
||||
mInputStream = mSocket.getInputStream();
|
||||
@@ -45,10 +40,14 @@ public class NetworkClient extends Client {
|
||||
mOutputStream = mSocket.getOutputStream();
|
||||
// Pairing.
|
||||
Random aRandom = new Random();
|
||||
String aPin = "" + aRandom.nextInt(10000);
|
||||
String aPin = "" + (aRandom.nextInt(9000) + 1000);
|
||||
while (aPin.length() < 4) {
|
||||
aPin = "0" + aPin; // Add leading zeros if necessary
|
||||
}
|
||||
Intent aIntent = new Intent(
|
||||
CommunicationService.MSG_PAIRING_STARTED);
|
||||
aIntent.putExtra("PIN", aPin);
|
||||
mPin = aPin;
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
|
||||
// Send out
|
||||
String aName = "Bob"; // TODO: get the proper name
|
||||
|
@@ -8,6 +8,8 @@ import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.libreoffice.impressremote.communication.Server.Protocol;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
@@ -93,6 +95,14 @@ public class ServerFinder {
|
||||
|
||||
mFinishRequested = false;
|
||||
|
||||
// TODO: Remove for production
|
||||
mServerList.put("10.0.2.2",
|
||||
new Server(Protocol.NETWORK, "10.0.2.2",
|
||||
"Android Emulator Localhost", System
|
||||
.currentTimeMillis()));
|
||||
Intent aIntent = new Intent(CommunicationService.MSG_SERVERLIST_CHANGED);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
|
||||
|
||||
if (mListenerThread == null) {
|
||||
mListenerThread = new Thread() {
|
||||
@Override
|
||||
|