d> 11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.io.File;
19
+import java.util.List;
20
+
21
+import android.graphics.Bitmap;
22
+
23
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
24
+import com.remoteyourcam.usb.ptp.model.ObjectInfo;
25
+
26
+public interface Camera {
27
+
28
+    public static class Property {
29
+        public static final int ShutterSpeed = 1;
30
+        public static final int ApertureValue = 2;
31
+        public static final int IsoSpeed = 3;
32
+        public static final int Whitebalance = 4;
33
+        public static final int ShootingMode = 5;
34
+        public static final int BatteryLevel = 6;
35
+        public static final int AvailableShots = 7;
36
+        public static final int ColorTemperature = 8;
37
+        public static final int FocusMode = 9;
38
+        public static final int PictureStyle = 10;
39
+        public static final int ExposureMeteringMode = 11;
40
+        public static final int FocusMeteringMode = 12;
41
+        public static final int CurrentFocusPoint = 13;
42
+        public static final int CurrentExposureIndicator = 14;
43
+        public static final int FocusPoints = 15;
44
+        public static final int ExposureCompensation = 16;
45
+    }
46
+
47
+    public static class DriveLens {
48
+        public static final int Near = 1;
49
+        public static final int Far = 2;
50
+        public static final int Soft = 1;
51
+        public static final int Medium = 2;
52
+        public static final int Hard = 3;
53
+    }
54
+
55
+    public interface CameraListener {
56
+
57
+        void onCameraStarted(Camera camera);
58
+
59
+        void onCameraStopped(Camera camera);
60
+
61
+        void onNoCameraFound();
62
+
63
+        void onError(String message);
64
+
65
+        void onPropertyChanged(int property, int value);
66
+
67
+        void onPropertyStateChanged(int property, boolean enabled);
68
+
69
+        void onPropertyDescChanged(int property, int[] values);
70
+
71
+        void onLiveViewStarted();
72
+
73
+        void onLiveViewData(LiveViewData data);
74
+
75
+        void onLiveViewStopped();
76
+
77
+        void onCapturedPictureReceived(int objectHandle, String filename, Bitmap thumbnail, Bitmap bitmap);
78
+
79
+        void onBulbStarted();
80
+
81
+        void onBulbExposureTime(int seconds);
82
+
83
+        void onBulbStopped();
84
+
85
+        void onFocusStarted();
86
+
87
+        void onFocusEnded(boolean hasFocused);
88
+
89
+        void onFocusPointsChanged();
90
+
91
+        void onObjectAdded(int handle, int format);
92
+    }
93
+
94
+    // callbacks aren't on UI thread
95
+    public interface WorkerListener {
96
+        void onWorkerStarted();
97
+
98
+        void onWorkerEnded();
99
+    }
100
+
101
+    // callbacks aren't on UI thread
102
+    public interface StorageInfoListener {
103
+        void onStorageFound(int handle, String label);
104
+
105
+        void onAllStoragesFound();
106
+
107
+        void onImageHandlesRetrieved(int[] handles);
108
+    }
109
+
110
+    public interface RetrieveImageInfoListener {
111
+        void onImageInfoRetrieved(int objectHandle, ObjectInfo objectInfo, Bitmap thumbnail);
112
+    }
113
+
114
+    public interface RetrieveImageListener {
115
+        void onImageRetrieved(int objectHandle, Bitmap image);
116
+    }
117
+
118
+    void setWorkerListener(WorkerListener listener);
119
+
120
+    void setCapturedPictureSampleSize(int sampleSize);
121
+
122
+    String getDeviceName();
123
+
124
+    boolean isSessionOpen();
125
+
126
+    int getProperty(int property);
127
+
128
+    boolean getPropertyEnabledState(int property);
129
+
130
+    int[] getPropertyDesc(int property);
131
+
132
+    void setProperty(int property, int value);
133
+
134
+    String propertyToString(int property, int value);
135
+
136
+    Integer propertyToIcon(int property, int value);
137
+
138
+    String getBiggestPropertyValue(int property);
139
+
140
+    void focus();
141
+
142
+    boolean isAutoFocusSupported();
143
+
144
+    void capture();
145
+
146
+    boolean isLiveViewSupported();
147
+
148
+    boolean isLiveViewAfAreaSupported();
149
+
150
+    boolean isHistogramSupported();
151
+
152
+    boolean isLiveViewOpen();
153
+
154
+    void setLiveView(boolean enabled);
155
+
156
+    void getLiveViewPicture(LiveViewData reuse);
157
+
158
+    /**
159
+     * Sets the center point of the auto focus frame in Live view.
160
+     *
161
+     * @param posx
162
+     *            range 0.0 (left) - 1.0 (right)
163
+     * @param posy
164
+     *            range 0.0 (top) - 1.0 (bottom)
165
+     */
166
+    void setLiveViewAfArea(float posx, float posy);
167
+
168
+    boolean isDriveLensSupported();
169
+
170
+    void driveLens(int driveDirection, int pulses);
171
+
172
+    boolean isSettingPropertyPossible(int property);
173
+
174
+    void writeDebugInfo(File out);
175
+
176
+    String getDeviceInfo();
177
+
178
+    List<FocusPoint> getFocusPoints();
179
+
180
+    void retrievePicture(int objectHandle);
181
+
182
+    void retrieveStorages(StorageInfoListener listener);
183
+
184
+    void retrieveImageHandles(StorageInfoListener listener, int storageId, int objectFormat);
185
+
186
+    void retrieveImageInfo(RetrieveImageInfoListener listener, int objectHandle);
187
+
188
+    void retrieveImage(RetrieveImageListener listener, int objectHandle);
189
+}

+ 179 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/EosCamera.java

@@ -0,0 +1,179 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.util.ArrayList;
19
+import java.util.List;
20
+import java.util.Set;
21
+
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
23
+import com.remoteyourcam.usb.ptp.commands.SimpleCommand;
24
+import com.remoteyourcam.usb.ptp.commands.eos.EosEventCheckCommand;
25
+import com.remoteyourcam.usb.ptp.commands.eos.EosGetLiveViewPictureCommand;
26
+import com.remoteyourcam.usb.ptp.commands.eos.EosOpenSessionAction;
27
+import com.remoteyourcam.usb.ptp.commands.eos.EosSetLiveViewAction;
28
+import com.remoteyourcam.usb.ptp.commands.eos.EosSetPropertyCommand;
29
+import com.remoteyourcam.usb.ptp.commands.eos.EosTakePictureCommand;
30
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
31
+
32
+public class EosCamera extends PtpCamera {
33
+
34
+    public EosCamera(PtpUsbConnection connection, CameraListener listener, WorkerListener workerListener) {
35
+        super(connection, listener, workerListener);
36
+
37
+        addPropertyMapping(Camera.Property.ShutterSpeed, PtpConstants.Property.EosShutterSpeed);
38
+        addPropertyMapping(Camera.Property.ApertureValue, PtpConstants.Property.EosApertureValue);
39
+        addPropertyMapping(Camera.Property.IsoSpeed, PtpConstants.Property.EosIsoSpeed);
40
+        addPropertyMapping(Camera.Property.Whitebalance, PtpConstants.Property.EosWhitebalance);
41
+        addPropertyMapping(Camera.Property.ShootingMode, PtpConstants.Property.EosShootingMode);
42
+        addPropertyMapping(Camera.Property.AvailableShots, PtpConstants.Property.EosAvailableShots);
43
+        addPropertyMapping(Camera.Property.ColorTemperature, PtpConstants.Property.EosColorTemperature);
44
+        addPropertyMapping(Camera.Property.FocusMode, PtpConstants.Property.EosAfMode);
45
+        addPropertyMapping(Camera.Property.PictureStyle, PtpConstants.Property.EosPictureStyle);
46
+        addPropertyMapping(Camera.Property.ExposureMeteringMode, PtpConstants.Property.EosMeteringMode);
47
+        addPropertyMapping(Camera.Property.ExposureCompensation, PtpConstants.Property.EosExposureCompensation);
48
+
49
+        histogramSupported = true;
50
+    }
51
+
52
+    @Override
53
+    protected void onOperationCodesReceived(Set<Integer> operations) {
54
+        if (operations.contains(Operation.EosGetLiveViewPicture)) {
55
+            liveViewSupported = true;
56
+        }
57
+        if (operations.contains(Operation.EosBulbStart) && operations.contains(Operation.EosBulbEnd)) {
58
+            bulbSupported = true;
59
+        }
60
+        if (operations.contains(Operation.EosDriveLens)) {
61
+            driveLensSupported = true;
62
+        }
63
+        if (operations.contains(Operation.EosRemoteReleaseOn) && operations.contains(Operation.EosRemoteReleaseOff)) {
64
+            //autoFocusSupported = true;
65
+        }
66
+    }
67
+
68
+    public void onEventDirItemCreated(int objectHandle, int storageId, int objectFormat, String filename) {
69
+        onEventObjectAdded(objectHandle, objectFormat);
70
+    }
71
+
72
+    @Override
73
+    protected void openSession() {
74
+        queue.add(new EosOpenSessionAction(this));
75
+    }
76
+
77
+    @Override
78
+    protected void queueEventCheck() {
79
+        queue.add(new EosEventCheckCommand(this));
80
+    }
81
+
82
+    @Override
83
+    public void focus() {
84
+        //queue.add(new SimpleCommand(this, Operation.EosRemoteReleaseOn, 1, 0));
85
+    }
86
+
87
+    @Override
88
+    public void capture() {
89
+        if (isBulbCurrentShutterSpeed()) {
90
+            queue.add(new SimpleCommand(this, cameraIsCapturing ? Operation.EosBulbEnd : Operation.EosBulbStart));
91
+        } else {
92
+            queue.add(new EosTakePictureCommand(this));
93
+        }
94
+    }
95
+
96
+    @Override
97
+    public void setProperty(int property, int value) {
98
+        if (properties.containsKey(property)) {
99
+            queue.add(new EosSetPropertyCommand(this, virtualToPtpProperty.get(property), value));
100
+        }
101
+    }
102
+
103
+    @Override
104
+    public void setLiveView(boolean enabled) {
105
+        if (liveViewSupported) {
106
+            queue.add(new EosSetLiveViewAction(this, enabled));
107
+        }
108
+    }
109
+
110
+    @Override
111
+    public void getLiveViewPicture(LiveViewData data) {
112
+        if (liveViewOpen) {
113
+            queue.add(new EosGetLiveViewPictureCommand(this, data));
114
+        }
115
+    }
116
+
117
+    @Override
118
+    protected boolean isBulbCurrentShutterSpeed() {
119
+        Integer value = ptpProperties.get(PtpConstants.Property.EosShutterSpeed);
120
+        return bulbSupported && value != null && value == PtpPropertyHelper.EOS_SHUTTER_SPEED_BULB;
121
+    }
122
+
123
+    @Override
124
+    public void driveLens(int driveDirection, int pulses) {
125
+        if (driveLensSupported && liveViewOpen) {
126
+            int value = driveDirection == Camera.DriveLens.Near ? 0 : 0x8000;
127
+            switch (pulses) {
128
+            case DriveLens.Hard:
129
+                value |= 0x0003;
130
+                break;
131
+            case DriveLens.Medium:
132
+                value |= 0x0002;
133
+                break;
134
+            case DriveLens.Soft:
135
+            default:
136
+                value |= 0x0001;
137
+                break;
138
+            }
139
+            queue.add(new SimpleCommand(this, PtpConstants.Operation.EosDriveLens, value));
140
+        }
141
+    }
142
+
143
+    @Override
144
+    public boolean isSettingPropertyPossible(int property) {
145
+        Integer mode = ptpProperties.get(PtpConstants.Property.EosShootingMode);
146
+        Integer wb = ptpProperties.get(PtpConstants.Property.WhiteBalance);
147
+        if (mode == null) {
148
+            return false;
149
+        }
150
+        switch (property) {
151
+        case Property.ShutterSpeed:
152
+            return mode == 3 || mode == 1;
153
+        case Property.ApertureValue:
154
+            return mode == 3 || mode == 2;
155
+        case Property.IsoSpeed:
156
+        case Property.Whitebalance:
157
+        case Property.ExposureMeteringMode:
158
+            return mode >= 0 && mode <= 6;
159
+        case Property.FocusPoints:
160
+            return false;
161
+        case Property.ExposureCompensation:
162
+            return mode == 0 || mode == 1 || mode == 2 || mode == 5 || mode == 6;
163
+        case Property.ColorTemperature:
164
+            return wb != null && wb == 9;
165
+        default:
166
+            return true;
167
+        }
168
+    }
169
+
170
+    @Override
171
+    public void setLiveViewAfArea(float posx, float posy) {
172
+        // TODO Auto-generated method stub
173
+    }
174
+
175
+    @Override
176
+    public List<FocusPoint> getFocusPoints() {
177
+        return new ArrayList<FocusPoint>();
178
+    }
179
+}

+ 30 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/EosConstants.java

@@ -0,0 +1,30 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+public class EosConstants {
19
+
20
+    public static class EvfOutputDevice {
21
+        public static final int DISABLE = 0x0;
22
+        public static final int TFT = 0x01;
23
+        public static final int PC = 0x02;
24
+    }
25
+
26
+    public static class EvfMode {
27
+        public static final int DISABLE = 0;
28
+        public static final int ENABLE = 1;
29
+    }
30
+}

+ 30 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/FocusPoint.java

@@ -0,0 +1,30 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+public class FocusPoint {
19
+    public int id;
20
+    public float posx;
21
+    public float posy;
22
+    public float radius;
23
+
24
+    public FocusPoint(int id, float posx, float posy, float radius) {
25
+        this.id = id;
26
+        this.posx = posx;
27
+        this.posy = posy;
28
+        this.radius = radius;
29
+    }
30
+}

+ 374 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/NikonCamera.java

@@ -0,0 +1,374 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.util.ArrayList;
19
+import java.util.HashSet;
20
+import java.util.List;
21
+import java.util.Set;
22
+
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+import com.remoteyourcam.usb.ptp.commands.GetDevicePropDescCommand;
25
+import com.remoteyourcam.usb.ptp.commands.InitiateCaptureCommand;
26
+import com.remoteyourcam.usb.ptp.commands.RetrieveAddedObjectInfoAction;
27
+import com.remoteyourcam.usb.ptp.commands.SimpleCommand;
28
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonAfDriveCommand;
29
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonCloseSessionAction;
30
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonEventCheckCommand;
31
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonGetLiveViewImageAction;
32
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonGetLiveViewImageCommand;
33
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonOpenSessionAction;
34
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonStartLiveViewAction;
35
+import com.remoteyourcam.usb.ptp.commands.nikon.NikonStopLiveViewAction;
36
+import com.remoteyourcam.usb.ptp.model.DevicePropDesc;
37
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
38
+
39
+public class NikonCamera extends PtpCamera {
40
+
41
+    private Set<Integer> supportedOperations;
42
+    private int[] vendorPropCodes = new int[0];
43
+    private int enableAfAreaPoint;
44
+    private boolean gotNikonShutterSpeed;
45
+    private boolean liveViewStoppedInternal;
46
+
47
+    public NikonCamera(PtpUsbConnection connection, CameraListener listener, WorkerListener workerListener) {
48
+        super(connection, listener, workerListener);
49
+
50
+        histogramSupported = false;
51
+    }
52
+
53
+    @Override
54
+    protected void onOperationCodesReceived(Set<Integer> operations) {
55
+        supportedOperations = operations;
56
+        if (operations.contains(Operation.NikonGetLiveViewImage) && operations.contains(Operation.NikonStartLiveView)
57
+                && operations.contains(Operation.NikonEndLiveView)) {
58
+            liveViewSupported = true;
59
+        }
60
+        if (operations.contains(Operation.NikonMfDrive)) {
61
+            driveLensSupported = true;
62
+        }
63
+        if (operations.contains(Operation.NikonChangeAfArea)) {
64
+            liveViewAfAreaSupported = true;
65
+        }
66
+        if (operations.contains(Operation.NikonAfDrive)) {
67
+            autoFocusSupported = true;
68
+        }
69
+    }
70
+
71
+    @Override
72
+    public void onPropertyChanged(int property, int value) {
73
+        super.onPropertyChanged(property, value);
74
+        if (property == PtpConstants.Property.NikonEnableAfAreaPoint) {
75
+            enableAfAreaPoint = value;
76
+            handler.post(new Runnable() {
77
+                @Override
78
+                public void run() {
79
+                    if (listener != null) {
80
+                        listener.onFocusPointsChanged();
81
+                    }
82
+                }
83
+            });
84
+        }
85
+    }
86
+
87
+    @Override
88
+    public void onPropertyDescChanged(int property, DevicePropDesc desc) {
89
+        if (!gotNikonShutterSpeed) {
90
+            if (property == PtpConstants.Property.NikonShutterSpeed) {
91
+                // some cameras have this properties with only 2/3 values
92
+                if (desc.description.length <= 4) {
93
+                    return;
94
+                }
95
+                addPropertyMapping(Camera.Property.ShutterSpeed, PtpConstants.Property.NikonShutterSpeed);
96
+                gotNikonShutterSpeed = true;
97
+            } else if (property == PtpConstants.Property.ExposureTime) {
98
+                addPropertyMapping(Camera.Property.ShutterSpeed, PtpConstants.Property.ExposureTime);
99
+                gotNikonShutterSpeed = true;
100
+            }
101
+        }
102
+        super.onPropertyDescChanged(property, desc);
103
+    }
104
+
105
+    private void onPropertyCodesReceived(Set<Integer> properties) {
106
+        if (properties.contains(PtpConstants.Property.NikonShutterSpeed)) {
107
+            queue.add(new GetDevicePropDescCommand(this, PtpConstants.Property.NikonShutterSpeed));
108
+        }
109
+        if (properties.contains(PtpConstants.Property.ExposureTime)) {
110
+            queue.add(new GetDevicePropDescCommand(this, PtpConstants.Property.ExposureTime));
111
+        }
112
+
113
+        addPropertyMapping(Camera.Property.ApertureValue, PtpConstants.Property.FNumber);
114
+        addPropertyMapping(Camera.Property.IsoSpeed, PtpConstants.Property.ExposureIndex);
115
+        addPropertyMapping(Camera.Property.Whitebalance, PtpConstants.Property.WhiteBalance);
116
+        addPropertyMapping(Camera.Property.ColorTemperature, PtpConstants.Property.NikonWbColorTemp);
117
+        addPropertyMapping(Camera.Property.ShootingMode, PtpConstants.Property.ExposureProgramMode);
118
+        addPropertyMapping(Camera.Property.BatteryLevel, PtpConstants.Property.BatteryLevel);
119
+        //addPropertyMapping(Camera.Property.AvailableShots, PtpConstants.Property);
120
+        addPropertyMapping(Camera.Property.FocusMode, PtpConstants.Property.FocusMode);
121
+        addPropertyMapping(Camera.Property.PictureStyle, PtpConstants.Property.NikonActivePicCtrlItem);
122
+        addPropertyMapping(Camera.Property.ExposureMeteringMode, PtpConstants.Property.ExposureMeteringMode);
123
+        addPropertyMapping(Camera.Property.FocusMeteringMode, PtpConstants.Property.FocusMeteringMode);
124
+        addPropertyMapping(Camera.Property.CurrentFocusPoint, PtpConstants.Property.NikonFocusArea);
125
+        addPropertyMapping(Camera.Property.CurrentExposureIndicator, PtpConstants.Property.NikonExposureIndicateStatus);
126
+        addPropertyMapping(Camera.Property.ExposureCompensation, PtpConstants.Property.ExposureBiasCompensation);
127
+
128
+        if (properties.contains(PtpConstants.Property.NikonEnableAfAreaPoint)) {
129
+            addInternalProperty(PtpConstants.Property.NikonEnableAfAreaPoint);
130
+        }
131
+
132
+        for (Integer property : properties) {
133
+            if (ptpToVirtualProperty.containsKey(property) || ptpInternalProperties.contains(property)) {
134
+                queue.add(new GetDevicePropDescCommand(this, property));
135
+            }
136
+        }
137
+    }
138
+
139
+    @Override
140
+    protected void openSession() {
141
+        queue.add(new NikonOpenSessionAction(this));
142
+    }
143
+
144
+    @Override
145
+    protected void closeSession() {
146
+        queue.add(new NikonCloseSessionAction(this));
147
+    }
148
+
149
+    @Override
150
+    protected void queueEventCheck() {
151
+        queue.add(new NikonEventCheckCommand(this));
152
+    }
153
+
154
+    @Override
155
+    public void onSessionOpened() {
156
+        super.onSessionOpened();
157
+        Set<Integer> properties = new HashSet<Integer>();
158
+        for (int i = 0; i < deviceInfo.devicePropertiesSupported.length; ++i) {
159
+            properties.add(deviceInfo.devicePropertiesSupported[i]);
160
+        }
161
+        for (int i = 0; i < vendorPropCodes.length; ++i) {
162
+            properties.add(vendorPropCodes[i]);
163
+        }
164
+        onPropertyCodesReceived(properties);
165
+    }
166
+
167
+    public void setVendorPropCodes(int[] vendorPropCodes) {
168
+        this.vendorPropCodes = vendorPropCodes;
169
+    }
170
+
171
+    public void onEventObjectAdded(int objectHandle) {
172
+        queue.add(new RetrieveAddedObjectInfoAction(this, objectHandle));
173
+    }
174
+
175
+    public void onEventCaptureComplete() {
176
+        //TODO
177
+    }
178
+
179
+    public boolean hasSupportForOperation(int operation) {
180
+        return supportedOperations.contains(operation);
181
+    }
182
+
183
+    @Override
184
+    public void driveLens(int driveDirection, int pulses) {
185
+        queue.add(new SimpleCommand(this, Operation.NikonMfDrive, driveDirection == DriveLens.Far ? 0x02 : 0x01,
186
+                pulses * 300));
187
+    }
188
+
189
+    @Override
190
+    protected boolean isBulbCurrentShutterSpeed() {
191
+        //TODO
192
+        return false;
193
+    }
194
+
195
+    public void onLiveViewStoppedInternal() {
196
+        liveViewStoppedInternal = true;
197
+    }
198
+
199
+    @Override
200
+    public void setLiveView(boolean enabled) {
201
+        liveViewStoppedInternal = false;
202
+        if (enabled) {
203
+            queue.add(new NikonStartLiveViewAction(this));
204
+        } else {
205
+            queue.add(new NikonStopLiveViewAction(this, true));
206
+        }
207
+    }
208
+
209
+    @Override
210
+    public void getLiveViewPicture(LiveViewData reuse) {
211
+        if (liveViewSupported && liveViewStoppedInternal) {
212
+            liveViewStoppedInternal = false;
213
+            queue.add(new NikonGetLiveViewImageAction(this, reuse));
214
+        } else {
215
+            queue.add(new NikonGetLiveViewImageCommand(this, reuse));
216
+        }
217
+    }
218
+
219
+    @Override
220
+    public boolean isSettingPropertyPossible(int property) {
221
+        Integer mode = ptpProperties.get(PtpConstants.Property.ExposureProgramMode);
222
+        Integer wb = ptpProperties.get(PtpConstants.Property.WhiteBalance);
223
+        if (mode == null) {
224
+            return false;
225
+        }
226
+        switch (property) {
227
+        case Property.ShutterSpeed:
228
+            return mode == 4 || mode == 1;
229
+        case Property.ApertureValue:
230
+            return mode == 3 || mode == 1;
231
+        case Property.IsoSpeed: //TODO this should only be disabled for DIP when isoautosetting is on
232
+        case Property.Whitebalance:
233
+        case Property.ExposureMeteringMode:
234
+        case Property.ExposureCompensation:
235
+            return mode < 0x8010;
236
+        case Property.FocusPoints:
237
+            return true;
238
+        case Property.ColorTemperature:
239
+            return wb != null && wb == 0x8012;
240
+        default:
241
+            return true;
242
+        }
243
+    }
244
+
245
+    @Override
246
+    public void focus() {
247
+        queue.add(new NikonAfDriveCommand(this));
248
+    }
249
+
250
+    @Override
251
+    public void capture() {
252
+        if (liveViewOpen) {
253
+            queue.add(new NikonStopLiveViewAction(this, false));
254
+        }
255
+        queue.add(new InitiateCaptureCommand(this));
256
+    }
257
+
258
+    private int wholeWidth;
259
+    private int wholeHeight;
260
+    private int afAreaWidth;
261
+    private int afAreaHeight;
262
+
263
+    @Override
264
+    public void onLiveViewReceived(LiveViewData data) {
265
+        super.onLiveViewReceived(data);
266
+        if (data != null) {
267
+            wholeWidth = data.nikonWholeWidth;
268
+            wholeHeight = data.nikonWholeHeight;
269
+            afAreaWidth = data.nikonAfFrameWidth;
270
+            afAreaHeight = data.nikonAfFrameHeight;
271
+        }
272
+    }
273
+
274
+    @Override
275
+    public void setLiveViewAfArea(float posx, float posy) {
276
+        if (supportedOperations.contains(Operation.NikonChangeAfArea)) {
277
+            float centerx = Math.min(wholeWidth - (afAreaWidth >> 1), Math.max(afAreaWidth >> 1, posx * wholeWidth));
278
+            float centery = Math
279
+                    .min(wholeHeight - (afAreaHeight >> 1), Math.max(afAreaHeight >> 1, posy * wholeHeight));
280
+            queue.add(new SimpleCommand(this, PtpConstants.Operation.NikonChangeAfArea, (int) centerx, (int) centery));
281
+        }
282
+    }
283
+
284
+    @Override
285
+    public List<FocusPoint> getFocusPoints() {
286
+        List<FocusPoint> points = new ArrayList<FocusPoint>();
287
+        switch (productId) {
288
+        case PtpConstants.Product.NikonD40:
289
+        /* TODO no productId for D60 case PtpConstants.Product.NikonD60: */{
290
+            points.add(new FocusPoint(0, 0.5f, 0.5f, 0.04f));
291
+            points.add(new FocusPoint(0, 0.30f, 0.5f, 0.04f));
292
+            points.add(new FocusPoint(0, 0.70f, 0.5f, 0.04f));
293
+            return points;
294
+        }
295
+        case PtpConstants.Product.NikonD200:
296
+        case PtpConstants.Product.NikonD80: {
297
+            points.add(new FocusPoint(0, 0.5f, 0.5f, 0.04f));
298
+            points.add(new FocusPoint(1, 0.5f, 0.29f, 0.04f));
299
+            points.add(new FocusPoint(2, 0.5f, 0.71f, 0.04f));
300
+            points.add(new FocusPoint(3, 0.33f, 0.5f, 0.04f));
301
+            points.add(new FocusPoint(4, 0.67f, 0.5f, 0.04f));
302
+            points.add(new FocusPoint(5, 0.22f, 0.5f, 0.04f));
303
+            points.add(new FocusPoint(6, 0.78f, 0.5f, 0.04f));
304
+            points.add(new FocusPoint(7, 0.33f, 0.39f, 0.04f));
305
+            points.add(new FocusPoint(8, 0.67f, 0.39f, 0.04f));
306
+            points.add(new FocusPoint(9, 0.33f, 0.61f, 0.04f));
307
+            points.add(new FocusPoint(10, 0.67f, 0.61f, 0.04f));
308
+            return points;
309
+        }
310
+        case PtpConstants.Product.NikonD5000:
311
+        case PtpConstants.Product.NikonD90: {
312
+            points.add(new FocusPoint(1, 0.5f, 0.5f, 0.04f));
313
+            points.add(new FocusPoint(2, 0.5f, 0.3f, 0.04f));
314
+            points.add(new FocusPoint(3, 0.5f, 0.7f, 0.04f));
315
+            points.add(new FocusPoint(4, 0.33f, 0.5f, 0.04f));
316
+            points.add(new FocusPoint(5, 0.33f, 0.35f, 0.04f));
317
+            points.add(new FocusPoint(6, 0.33f, 0.65f, 0.04f));
318
+            points.add(new FocusPoint(7, 0.22f, 0.5f, 0.04f));
319
+            points.add(new FocusPoint(8, 0.67f, 0.5f, 0.04f));
320
+            points.add(new FocusPoint(9, 0.67f, 0.35f, 0.04f));
321
+            points.add(new FocusPoint(10, 0.67f, 0.65f, 0.04f));
322
+            points.add(new FocusPoint(11, 0.78f, 0.5f, 0.04f));
323
+            return points;
324
+        }
325
+        case PtpConstants.Product.NikonD300:
326
+            //case PtpConstants.Product.NikonD700: same id as d300
327
+        case PtpConstants.Product.NikonD300S:
328
+        case PtpConstants.Product.NikonD3:
329
+        case PtpConstants.Product.NikonD3S:
330
+        case PtpConstants.Product.NikonD3X: {
331
+            points.add(new FocusPoint(1, 0.5f, 0.5f, 0.035f));
332
+            points.add(new FocusPoint(3, 0.5f, 0.36f, 0.035f));
333
+            points.add(new FocusPoint(5, 0.5f, 0.64f, 0.035f));
334
+
335
+            points.add(new FocusPoint(21, 0.65f, 0.5f, 0.035f));
336
+            points.add(new FocusPoint(23, 0.65f, 0.4f, 0.035f));
337
+            points.add(new FocusPoint(25, 0.65f, 0.6f, 0.035f));
338
+            points.add(new FocusPoint(31, 0.75f, 0.5f, 0.035f));
339
+
340
+            points.add(new FocusPoint(39, 0.35f, 0.5f, 0.035f));
341
+            points.add(new FocusPoint(41, 0.35f, 0.4f, 0.035f));
342
+            points.add(new FocusPoint(43, 0.35f, 0.6f, 0.035f));
343
+            points.add(new FocusPoint(49, 0.25f, 0.5f, 0.035f));
344
+
345
+            if (enableAfAreaPoint == 0) {
346
+                //TODO has more points when EnableAFAreaPoint is 0
347
+            }
348
+            return points;
349
+        }
350
+        case PtpConstants.Product.NikonD7000: {
351
+            points.add(new FocusPoint(1, 0.5f, 0.5f, 0.035f));
352
+            points.add(new FocusPoint(3, 0.5f, 0.32f, 0.035f));
353
+            points.add(new FocusPoint(5, 0.5f, 0.68f, 0.035f));
354
+
355
+            points.add(new FocusPoint(19, 0.68f, 0.5f, 0.035f));
356
+            points.add(new FocusPoint(20, 0.68f, 0.4f, 0.035f));
357
+            points.add(new FocusPoint(21, 0.68f, 0.6f, 0.035f));
358
+            points.add(new FocusPoint(25, 0.80f, 0.5f, 0.035f));
359
+
360
+            points.add(new FocusPoint(31, 0.32f, 0.5f, 0.035f));
361
+            points.add(new FocusPoint(32, 0.32f, 0.4f, 0.035f));
362
+            points.add(new FocusPoint(33, 0.32f, 0.6f, 0.035f));
363
+            points.add(new FocusPoint(37, 0.20f, 0.5f, 0.035f));
364
+
365
+            if (enableAfAreaPoint == 0) {
366
+                //TODO has more points when EnableAFAreaPoint is 0
367
+            }
368
+            return points;
369
+        }
370
+        default:
371
+            return points;
372
+        }
373
+    }
374
+}

+ 162 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PacketUtil.java

@@ -0,0 +1,162 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import android.util.Log;
21
+
22
+public class PacketUtil {
23
+
24
+    public static int[] readU32Array(ByteBuffer b) {
25
+        int len = b.getInt();
26
+        int[] a = new int[len];
27
+        for (int i = 0; i < len; ++i) {
28
+            a[i] = b.getInt();
29
+        }
30
+        return a;
31
+    }
32
+
33
+    public static int[] readU16Array(ByteBuffer b) {
34
+        int len = b.getInt();
35
+        int[] a = new int[len];
36
+        for (int i = 0; i < len; ++i) {
37
+            a[i] = b.getShort() & 0xFFFF;
38
+        }
39
+        return a;
40
+    }
41
+
42
+    public static void writeU16Array(ByteBuffer b, int[] a) {
43
+        b.putInt(a.length);
44
+        for (int v : a) {
45
+            b.putShort((short) v);
46
+        }
47
+    }
48
+
49
+    public static int[] readU8Array(ByteBuffer b) {
50
+        int len = b.getInt();
51
+        int[] a = new int[len];
52
+        for (int i = 0; i < len; ++i) {
53
+            a[i] = b.get() & 0xFF;
54
+        }
55
+        return a;
56
+    }
57
+
58
+    public static int[] readU32Enumeration(ByteBuffer b) {
59
+        int len = b.getShort() & 0xFFFF;
60
+        int[] a = new int[len];
61
+        for (int i = 0; i < len; ++i) {
62
+            a[i] = b.getInt();
63
+        }
64
+        return a;
65
+    }
66
+
67
+    public static int[] readS16Enumeration(ByteBuffer b) {
68
+        int len = b.getShort() & 0xFFFF;
69
+        int[] a = new int[len];
70
+        for (int i = 0; i < len; ++i) {
71
+            a[i] = b.getShort();
72
+        }
73
+        return a;
74
+    }
75
+
76
+    public static int[] readU16Enumeration(ByteBuffer b) {
77
+        int len = b.getShort() & 0xFFFF;
78
+        int[] a = new int[len];
79
+        for (int i = 0; i < len; ++i) {
80
+            a[i] = b.getShort() & 0xFFFF;
81
+        }
82
+        return a;
83
+    }
84
+
85
+    public static int[] readU8Enumeration(ByteBuffer b) {
86
+        int len = b.getShort() & 0xFFFF;
87
+        int[] a = new int[len];
88
+        for (int i = 0; i < len; ++i) {
89
+            a[i] = b.get() & 0xFF;
90
+        }
91
+        return a;
92
+    }
93
+
94
+    public static String readString(ByteBuffer b) {
95
+        int len = b.get() & 0xFF;
96
+        if (len > 0) {
97
+            char[] ch = new char[len - 1];
98
+            for (int i = 0; i < len - 1; ++i) {
99
+                ch[i] = b.getChar();
100
+            }
101
+            // read '\0'
102
+            b.getChar();
103
+            return String.copyValueOf(ch);
104
+        }
105
+        return "";
106
+    }
107
+
108
+    public static void writeString(ByteBuffer b, String s) {
109
+        b.put((byte) s.length());
110
+        if (s.length() > 0) {
111
+            for (int i = 0; i < s.length(); ++i) {
112
+                b.putShort((short) s.charAt(i));
113
+            }
114
+            b.putShort((short) 0);
115
+        }
116
+    }
117
+
118
+    public static String hexDumpToString(byte[] a, int offset, int len) {
119
+        int lines = len / 16;
120
+        int rest = len % 16;
121
+
122
+        StringBuilder b = new StringBuilder((lines + 1) * 97);
123
+
124
+        for (int i = 0; i < lines; ++i) {
125
+            b.append(String.format("%04x ", i * 16));
126
+            for (int k = 0; k < 16; ++k) {
127
+                b.append(String.format("%02x ", a[offset + i * 16 + k]));
128
+            }
129
+            for (int k = 0; k < 16; ++k) {
130
+                char ch = (char) a[offset + i * 16 + k];
131
+                b.append(ch >= 0x20 && ch <= 0x7E ? ch : '.');
132
+            }
133
+            b.append('\n');
134
+        }
135
+
136
+        if (rest != 0) {
137
+            b.append(String.format("%04x ", lines * 16));
138
+            for (int k = 0; k < rest; ++k) {
139
+                b.append(String.format("%02x ", a[offset + lines * 16 + k]));
140
+            }
141
+            for (int k = 0; k < (16 - rest) * 3; ++k) {
142
+                b.append(' ');
143
+            }
144
+            for (int k = 0; k < rest; ++k) {
145
+                char ch = (char) a[offset + lines * 16 + k];
146
+                b.append(ch >= 0x20 && ch <= 0x7E ? ch : '.');
147
+            }
148
+            b.append('\n');
149
+        }
150
+
151
+        return b.toString();
152
+    }
153
+
154
+    public static void logHexdump(String tag, byte[] a, int offset, int len) {
155
+        Log.i(tag, hexDumpToString(a, offset, len));
156
+    }
157
+
158
+    public static void logHexdump(String tag, byte[] a, int len) {
159
+        logHexdump(tag, a, 0, len);
160
+    }
161
+
162
+}

+ 35 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpAction.java

@@ -0,0 +1,35 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+/**
19
+ * {@code PtpActions} execute one or more {@code Command}s against the actual
20
+ * hardware.
21
+ *
22
+ * A {@code PtpCamera} queues {@Code PtpAction}s into the worker thread
23
+ * for further communications. The action should do the communication via the
24
+ * given {@code IO} interface and based on the received data and response repor
25
+ * back to the actual {@code PtpCamera}.
26
+ */
27
+public interface PtpAction {
28
+
29
+    void exec(PtpCamera.IO io);
30
+
31
+    /**
32
+     * Reset an already used action so it can be re-used.
33
+     */
34
+    void reset();
35
+}

+ 890 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpCamera.java

@@ -0,0 +1,890 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.io.File;
19
+import java.io.FileWriter;
20
+import java.io.IOException;
21
+import java.nio.ByteBuffer;
22
+import java.nio.ByteOrder;
23
+import java.util.Arrays;
24
+import java.util.HashMap;
25
+import java.util.HashSet;
26
+import java.util.Map;
27
+import java.util.Set;
28
+import java.util.concurrent.LinkedBlockingQueue;
29
+import java.util.concurrent.TimeUnit;
30
+
31
+import android.graphics.Bitmap;
32
+import android.hardware.usb.UsbRequest;
33
+import android.os.Handler;
34
+import android.util.Log;
35
+
36
+import org.acra.ErrorReporter;
37
+
38
+import com.remoteyourcam.usb.AppConfig;
39
+import com.remoteyourcam.usb.ptp.commands.CloseSessionCommand;
40
+import com.remoteyourcam.usb.ptp.commands.Command;
41
+import com.remoteyourcam.usb.ptp.commands.GetDeviceInfoCommand;
42
+import com.remoteyourcam.usb.ptp.commands.GetDevicePropValueCommand;
43
+import com.remoteyourcam.usb.ptp.commands.GetObjectHandlesCommand;
44
+import com.remoteyourcam.usb.ptp.commands.GetStorageInfosAction;
45
+import com.remoteyourcam.usb.ptp.commands.InitiateCaptureCommand;
46
+import com.remoteyourcam.usb.ptp.commands.OpenSessionCommand;
47
+import com.remoteyourcam.usb.ptp.commands.RetrieveImageAction;
48
+import com.remoteyourcam.usb.ptp.commands.RetrieveImageInfoAction;
49
+import com.remoteyourcam.usb.ptp.commands.RetrievePictureAction;
50
+import com.remoteyourcam.usb.ptp.commands.SetDevicePropValueCommand;
51
+import com.remoteyourcam.usb.ptp.model.DeviceInfo;
52
+import com.remoteyourcam.usb.ptp.model.DevicePropDesc;
53
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
54
+
55
+public abstract class PtpCamera implements Camera {
56
+
57
+    public interface IO {
58
+        void handleCommand(Command command);
59
+    }
60
+
61
+    enum State {
62
+        // initial state
63
+        Starting,
64
+        // open session
65
+        Active,
66
+        // someone has asked to close session
67
+        Stoping,
68
+        // thread has stopped
69
+        Stopped,
70
+        // error happened
71
+        Error
72
+    }
73
+
74
+    private static final String TAG = PtpCamera.class.getSimpleName();
75
+
76
+    private final WorkerThread workerThread = new WorkerThread();
77
+    private final PtpUsbConnection connection;
78
+
79
+    protected final Handler handler = new Handler();
80
+    protected final LinkedBlockingQueue<PtpAction> queue = new LinkedBlockingQueue<PtpAction>();
81
+    protected CameraListener listener;
82
+    protected State state;
83
+
84
+    private int transactionId;
85
+    protected DeviceInfo deviceInfo;
86
+
87
+    protected boolean histogramSupported;
88
+    protected boolean liveViewSupported;
89
+    protected boolean liveViewAfAreaSupported;
90
+    protected boolean liveViewOpen;
91
+
92
+    protected boolean bulbSupported;
93
+
94
+    protected boolean driveLensSupported;
95
+
96
+    protected boolean autoFocusSupported;
97
+
98
+    protected boolean cameraIsCapturing;
99
+
100
+    protected final Map<Integer, Integer> virtualToPtpProperty = new HashMap<Integer, Integer>();
101
+    protected final Map<Integer, Integer> ptpToVirtualProperty = new HashMap<Integer, Integer>();
102
+
103
+    // current property values and descriptions
104
+    protected final Map<Integer, DevicePropDesc> ptpPropertyDesc = new HashMap<Integer, DevicePropDesc>();
105
+    protected final Map<Integer, Integer> ptpProperties = new HashMap<Integer, Integer>();
106
+    protected final Map<Integer, Integer> properties = new HashMap<Integer, Integer>();
107
+    private final Map<Integer, int[]> propertyDescriptions = new HashMap<Integer, int[]>();
108
+    protected final Set<Integer> ptpInternalProperties = new HashSet<Integer>();
109
+
110
+    private final int vendorId;
111
+    protected final int productId;
112
+
113
+    private WorkerListener workerListener;
114
+    private int pictureSampleSize;
115
+
116
+    public PtpCamera(PtpUsbConnection connection, CameraListener listener, WorkerListener workerListener) {
117
+        this.connection = connection;
118
+        this.listener = listener;
119
+        this.workerListener = workerListener;
120
+        this.pictureSampleSize = 2;
121
+        state = State.Starting;
122
+        vendorId = connection.getVendorId();
123
+        productId = connection.getProductId();
124
+        queue.add(new GetDeviceInfoCommand(this));
125
+        openSession();
126
+        workerThread.start();
127
+        if (AppConfig.LOG) {
128
+            Log.i(TAG, String.format("Starting session for %04x %04x", vendorId, productId));
129
+        }
130
+    }
131
+
132
+    protected void addPropertyMapping(int virtual, int ptp) {
133
+        ptpToVirtualProperty.put(ptp, virtual);
134
+        virtualToPtpProperty.put(virtual, ptp);
135
+    }
136
+
137
+    protected void addInternalProperty(int ptp) {
138
+        ptpInternalProperties.add(ptp);
139
+    }
140
+
141
+    public void setListener(CameraListener listener) {
142
+        this.listener = listener;
143
+    }
144
+
145
+    public void shutdown() {
146
+        state = State.Stoping;
147
+        workerThread.lastEventCheck = System.currentTimeMillis() + 1000000L;
148
+        queue.clear();
149
+        if (liveViewOpen) {
150
+            //TODO
151
+            setLiveView(false);
152
+        }
153
+        closeSession();
154
+    }
155
+
156
+    public void shutdownHard() {
157
+        state = State.Stopped;
158
+        synchronized (workerThread) {
159
+            workerThread.stop = true;
160
+        }
161
+        if (connection != null) {
162
+            connection.close();
163
+            //TODO possible NPE, need to join workerThread
164
+            //connection = null;
165
+        }
166
+    }
167
+
168
+    public State getState() {
169
+        return state;
170
+    }
171
+
172
+    public int nextTransactionId() {
173
+        return transactionId++;
174
+    }
175
+
176
+    public int currentTransactionId() {
177
+        return transactionId;
178
+    }
179
+
180
+    public void resetTransactionId() {
181
+        transactionId = 0;
182
+    }
183
+
184
+    public int getProductId() {
185
+        return productId;
186
+    }
187
+
188
+    public void setDeviceInfo(DeviceInfo deviceInfo) {
189
+        if (AppConfig.LOG) {
190
+            Log.i(TAG, deviceInfo.toString());
191
+        }
192
+        if (AppConfig.USE_ACRA) {
193
+            try {
194
+                ErrorReporter.getInstance().putCustomData("deviceInfo", deviceInfo.toString());
195
+            } catch (Throwable e) {
196
+                // no fail
197
+            }
198
+        }
199
+        this.deviceInfo = deviceInfo;
200
+
201
+        Set<Integer> operations = new HashSet<Integer>();
202
+        for (int i = 0; i < deviceInfo.operationsSupported.length; ++i) {
203
+            operations.add(deviceInfo.operationsSupported[i]);
204
+        }
205
+
206
+        onOperationCodesReceived(operations);
207
+    }
208
+
209
+    public void enqueue(final Command cmd, int delay) {
210
+        handler.postDelayed(new Runnable() {
211
+            @Override
212
+            public void run() {
213
+                if (state == State.Active) {
214
+                    queue.add(cmd);
215
+                }
216
+            }
217
+        }, delay);
218
+    }
219
+
220
+    /**
221
+     * Deriving classes should override this method to get the set of supported
222
+     * operations of the camera. Based on this information functionality has to
223
+     * be enabled/disabled.
224
+     */
225
+    protected abstract void onOperationCodesReceived(Set<Integer> operations);
226
+
227
+    public int getPtpProperty(int property) {
228
+        Integer value = ptpProperties.get(property);
229
+        return value != null ? value : 0;
230
+    }
231
+
232
+    public void onSessionOpened() {
233
+        state = State.Active;
234
+        handler.post(new Runnable() {
235
+            @Override
236
+            public void run() {
237
+                if (listener != null) {
238
+                    listener.onCameraStarted(PtpCamera.this);
239
+                }
240
+            }
241
+        });
242
+    }
243
+
244
+    public void onSessionClosed() {
245
+        shutdownHard();
246
+        handler.post(new Runnable() {
247
+            @Override
248
+            public void run() {
249
+                if (listener != null) {
250
+                    listener.onCameraStopped(PtpCamera.this);
251
+                }
252
+            }
253
+        });
254
+    }
255
+
256
+    public void onPropertyChanged(int property, final int value) {
257
+        Log.i(TAG, "p " + property + " " + value);
258
+        ptpProperties.put(property, value);
259
+        final Integer virtual = ptpToVirtualProperty.get(property);
260
+        if (AppConfig.LOG) {
261
+            Log.d(TAG, String.format("onPropertyChanged %s %s(%d)", PtpConstants.propertyToString(property),
262
+                    virtual != null ? propertyToString(virtual, value) : "", value));
263
+        }
264
+        if (virtual != null) {
265
+            handler.post(new Runnable() {
266
+                @Override
267
+                public void run() {
268
+                    properties.put(virtual, value);
269
+                    if (listener != null) {
270
+                        listener.onPropertyChanged(virtual, value);
271
+                    }
272
+                }
273
+            });
274
+        }
275
+    }
276
+
277
+    public void onPropertyDescChanged(int property, final int[] values) {
278
+        //if (BuildConfig.LOG) {
279
+            Log.d(TAG,
280
+                    String.format("onPropertyDescChanged %s:\n%s", PtpConstants.propertyToString(property),
281
+                            Arrays.toString(values)));
282
+        //}
283
+        final Integer virtual = ptpToVirtualProperty.get(property);
284
+        if (virtual != null) {
285
+            handler.post(new Runnable() {
286
+                @Override
287
+                public void run() {
288
+                    propertyDescriptions.put(virtual, values);
289
+                    if (listener != null) {
290
+                        listener.onPropertyDescChanged(virtual, values);
291
+                    }
292
+                }
293
+            });
294
+        }
295
+    }
296
+
297
+    public void onPropertyDescChanged(int property, DevicePropDesc desc) {
298
+        ptpPropertyDesc.put(property, desc);
299
+        onPropertyDescChanged(property, desc.description);
300
+    }
301
+
302
+    public void onLiveViewStarted() {
303
+        liveViewOpen = true;
304
+        handler.post(new Runnable() {
305
+            @Override
306
+            public void run() {
307
+                if (listener != null) {
308
+                    listener.onLiveViewStarted();
309
+                }
310
+            }
311
+        });
312
+    }
313
+
314
+    public void onLiveViewRestarted() {
315
+        liveViewOpen = true;
316
+        handler.post(new Runnable() {
317
+            @Override
318
+            public void run() {
319
+                if (listener != null) {
320
+                    listener.onLiveViewStarted();
321
+                }
322
+            }
323
+        });
324
+    }
325
+
326
+    public void onLiveViewStopped() {
327
+        liveViewOpen = false;
328
+        handler.post(new Runnable() {
329
+            @Override
330
+            public void run() {
331
+                if (listener != null) {
332
+                    listener.onLiveViewStopped();
333
+                }
334
+            }
335
+        });
336
+    }
337
+
338
+    public void onLiveViewReceived(final LiveViewData data) {
339
+        handler.post(new Runnable() {
340
+            @Override
341
+            public void run() {
342
+                if (listener != null) {
343
+                    listener.onLiveViewData(data);
344
+                }
345
+            }
346
+        });
347
+    }
348
+
349
+    public void onPictureReceived(final int objectHandle, final String filename, final Bitmap thumbnail,
350
+            final Bitmap bitmap) {
351
+        handler.post(new Runnable() {
352
+            @Override
353
+            public void run() {
354
+                if (listener != null) {
355
+                    listener.onCapturedPictureReceived(objectHandle, filename, thumbnail, bitmap);
356
+                }
357
+            }
358
+        });
359
+    }
360
+
361
+    public void onEventCameraCapture(boolean started) {
362
+        cameraIsCapturing = started;
363
+        if (isBulbCurrentShutterSpeed()) {
364
+            handler.post(new Runnable() {
365
+                @Override
366
+                public void run() {
367
+                    if (listener != null) {
368
+                        if (cameraIsCapturing) {
369
+                            listener.onBulbStarted();
370
+                        } else {
371
+                            listener.onBulbStopped();
372
+                        }
373
+                    }
374
+                }
375
+            });
376
+        }
377
+    }
378
+
379
+    public void onEventDevicePropChanged(int property) {
380
+        if ((ptpToVirtualProperty.containsKey(property) || ptpInternalProperties.contains(property))
381
+                && ptpPropertyDesc.containsKey(property)) {
382
+            DevicePropDesc desc = ptpPropertyDesc.get(property);
383
+            queue.add(new GetDevicePropValueCommand(this, property, desc.datatype));
384
+        }
385
+    }
386
+
387
+    public void onEventObjectAdded(final int handle, final int format) {
388
+        handler.post(new Runnable() {
389
+            @Override
390
+            public void run() {
391
+                if (listener != null) {
392
+                    listener.onObjectAdded(handle, format);
393
+                }
394
+            }
395
+        });
396
+    }
397
+
398
+    public void onBulbExposureTime(final int seconds) {
399
+        if (seconds >= 0 && seconds <= 360000) {
400
+            handler.post(new Runnable() {
401
+                @Override
402
+                public void run() {
403
+                    if (listener != null) {
404
+                        listener.onBulbExposureTime(seconds);
405
+                    }
406
+                }
407
+            });
408
+        }
409
+    }
410
+
411
+    public void onFocusStarted() {
412
+        handler.post(new Runnable() {
413
+            @Override
414
+            public void run() {
415
+                if (listener != null) {
416
+                    listener.onFocusStarted();
417
+                }
418
+            }
419
+        });
420
+    }
421
+
422
+    public void onFocusEnded(final boolean hasFocused) {
423
+        handler.post(new Runnable() {
424
+            @Override
425
+            public void run() {
426
+                if (listener != null) {
427
+                    listener.onFocusEnded(hasFocused);
428
+                }
429
+            }
430
+        });
431
+    }
432
+
433
+    public void onDeviceBusy(PtpAction action, boolean requeue) {
434
+        if (AppConfig.LOG) {
435
+            Log.i(TAG, "onDeviceBusy, sleeping a bit");
436
+        }
437
+        if (requeue) {
438
+            action.reset();
439
+            queue.add(action);
440
+        }
441
+        try {
442
+            Thread.sleep(200);
443
+        } catch (InterruptedException e) {
444
+            // nop
445
+        }
446
+    }
447
+
448
+    public void onPtpWarning(final String message) {
449
+        if (AppConfig.LOG) {
450
+            Log.i(TAG, "onPtpWarning: " + message);
451
+        }
452
+    }
453
+
454
+    public void onPtpError(final String message) {
455
+        if (AppConfig.LOG) {
456
+            Log.e(TAG, "onPtpError: " + message);
457
+        }
458
+        state = State.Error;
459
+        if (state == State.Active) {
460
+            shutdown();
461
+        } else {
462
+            shutdownHard();
463
+        }
464
+        handler.post(new Runnable() {
465
+            @Override
466
+            public void run() {
467
+                if (listener != null) {
468
+                    listener.onError(message);
469
+                }
470
+            }
471
+        });
472
+    }
473
+
474
+    private void onUsbError(final String message) {
475
+        if (AppConfig.LOG) {
476
+            Log.e(TAG, "onUsbError: " + message);
477
+        }
478
+        queue.clear();
479
+        shutdownHard();
480
+        state = State.Error;
481
+        handler.post(new Runnable() {
482
+            @Override
483
+            public void run() {
484
+                if (listener != null) {
485
+                    listener.onError(String.format("Error in USB communication: %s", message));
486
+                }
487
+            }
488
+        });
489
+    }
490
+
491
+    protected abstract void queueEventCheck();
492
+
493
+    protected abstract boolean isBulbCurrentShutterSpeed();
494
+
495
+    private class WorkerThread extends Thread implements IO {
496
+        public boolean stop;
497
+
498
+        private int maxPacketOutSize;
499
+        private int maxPacketInSize;
500
+        private long lastEventCheck;
501
+        private UsbRequest r1;
502
+        private UsbRequest r2;
503
+        private UsbRequest r3;
504
+        private final int bigInSize = 0x4000;
505
+        // buffers for async data io, size bigInSize
506
+        private ByteBuffer bigIn1;
507
+        private ByteBuffer bigIn2;
508
+        private ByteBuffer bigIn3;
509
+        // buffer for small packets like command and response
510
+        private ByteBuffer smallIn;
511
+        // buffer containing full data out packet for processing
512
+        private int fullInSize = 0x4000;
513
+        private ByteBuffer fullIn;
514
+
515
+        @Override
516
+        public void run() {
517
+
518
+            notifyWorkStarted();
519
+
520
+            maxPacketOutSize = connection.getMaxPacketOutSize();
521
+            maxPacketInSize = connection.getMaxPacketInSize();
522
+
523
+            if (maxPacketOutSize <= 0 || maxPacketOutSize > 0xffff) {
524
+                onUsbError(String.format("Usb initialization error: out size invalid %d", maxPacketOutSize));
525
+                return;
526
+            }
527
+
528
+            if (maxPacketInSize <= 0 || maxPacketInSize > 0xffff) {
529
+                onUsbError(String.format("usb initialization error: in size invalid %d", maxPacketInSize));
530
+                return;
531
+            }
532
+
533
+            smallIn = ByteBuffer.allocate(Math.max(maxPacketInSize, maxPacketOutSize));
534
+            smallIn.order(ByteOrder.LITTLE_ENDIAN);
535
+
536
+            bigIn1 = ByteBuffer.allocate(bigInSize);
537
+            bigIn1.order(ByteOrder.LITTLE_ENDIAN);
538
+            bigIn2 = ByteBuffer.allocate(bigInSize);
539
+            bigIn2.order(ByteOrder.LITTLE_ENDIAN);
540
+            bigIn3 = ByteBuffer.allocate(bigInSize);
541
+            bigIn3.order(ByteOrder.LITTLE_ENDIAN);
542
+
543
+            fullIn = ByteBuffer.allocate(fullInSize);
544
+            fullIn.order(ByteOrder.LITTLE_ENDIAN);
545
+
546
+            r1 = connection.createInRequest();
547
+            r2 = connection.createInRequest();
548
+            r3 = connection.createInRequest();
549
+
550
+            while (true) {
551
+                synchronized (this) {
552
+                    if (stop) {
553
+                        break;
554
+                    }
555
+                }
556
+
557
+                if (lastEventCheck + AppConfig.EVENTCHECK_PERIOD < System.currentTimeMillis()) {
558
+                    lastEventCheck = System.currentTimeMillis();
559
+                    PtpCamera.this.queueEventCheck();
560
+                }
561
+
562
+                PtpAction action = null;
563
+                try {
564
+                    action = queue.poll(1000, TimeUnit.MILLISECONDS);
565
+                } catch (InterruptedException e) {
566
+                    // nop
567
+                }
568
+
569
+                if (action != null) {
570
+                    action.exec(this);
571
+                }
572
+            }
573
+            r3.close();
574
+            r2.close();
575
+            r1.close();
576
+
577
+            notifyWorkEnded();
578
+        }
579
+
580
+        @Override
581
+        public void handleCommand(Command command) {
582
+            if (AppConfig.LOG) {
583
+                Log.i(TAG, "handling command " + command.getClass().getSimpleName());
584
+            }
585
+
586
+            ByteBuffer b = smallIn;
587
+            b.position(0);
588
+            command.encodeCommand(b);
589
+
590
+            int outLen = b.position();
591
+
592
+            int res = connection.bulkTransferOut(b.array(), outLen, AppConfig.USB_TRANSFER_TIMEOUT);
593
+            if (res < outLen) {
594
+                onUsbError(String.format("Code CP %d %d", res, outLen));
595
+                return;
596
+            }
597
+
598
+            if (command.hasDataToSend()) {
599
+                b = ByteBuffer.allocate(connection.getMaxPacketOutSize());
600
+                b.order(ByteOrder.LITTLE_ENDIAN);
601
+                command.encodeData(b);
602
+                outLen = b.position();
603
+                res = connection.bulkTransferOut(b.array(), outLen, AppConfig.USB_TRANSFER_TIMEOUT);
604
+                if (res < outLen) {
605
+                    onUsbError(String.format("Code DP %d %d", res, outLen));
606
+                    return;
607
+                }
608
+            }
609
+
610
+            while (!command.hasResponseReceived()) {
611
+                int maxPacketSize = maxPacketInSize;
612
+                ByteBuffer in = smallIn;
613
+                in.position(0);
614
+
615
+                res = 0;
616
+                while (res == 0) {
617
+                    res = connection.bulkTransferIn(in.array(), maxPacketSize, AppConfig.USB_TRANSFER_TIMEOUT);
618
+                }
619
+                if (res < 12) {
620
+                    onUsbError(String.format("Couldn't read header, only %d bytes available!", res));
621
+                    return;
622
+                }
623
+
624
+                int read = res;
625
+                int length = in.getInt();
626
+                ByteBuffer infull = null;
627
+
628
+                if (read < length) {
629
+                    if (length > fullInSize) {
630
+                        fullInSize = (int) (length * 1.5);
631
+                        fullIn = ByteBuffer.allocate(fullInSize);
632
+                        fullIn.order(ByteOrder.LITTLE_ENDIAN);
633
+                    }
634
+                    infull = fullIn;
635
+                    infull.position(0);
636
+                    infull.put(in.array(), 0, read);
637
+                    maxPacketSize = bigInSize;
638
+
639
+                    int nextSize = Math.min(maxPacketSize, length - read);
640
+                    int nextSize2 = Math.max(0, Math.min(maxPacketSize, length - read - nextSize));
641
+                    int nextSize3 = 0;
642
+
643
+                    r1.queue(bigIn1, nextSize);
644
+
645
+                    if (nextSize2 > 0) {
646
+                        r2.queue(bigIn2, nextSize2);
647
+                    }
648
+
649
+                    while (read < length) {
650
+
651
+                        nextSize3 = Math.max(0, Math.min(maxPacketSize, length - read - nextSize - nextSize2));
652
+
653
+                        if (nextSize3 > 0) {
654
+                            bigIn3.position(0);
655
+                            r3.queue(bigIn3, nextSize3);
656
+                        }
657
+
658
+                        if (nextSize > 0) {
659
+                            connection.requestWait();
660
+                            System.arraycopy(bigIn1.array(), 0, infull.array(), read, nextSize);
661
+                            read += nextSize;
662
+                        }
663
+
664
+                        nextSize = Math.max(0, Math.min(maxPacketSize, length - read - nextSize2 - nextSize3));
665
+
666
+                        if (nextSize > 0) {
667
+                            bigIn1.position(0);
668
+                            r1.queue(bigIn1, nextSize);
669
+                        }
670
+
671
+                        if (nextSize2 > 0) {
672
+                            connection.requestWait();
673
+                            System.arraycopy(bigIn2.array(), 0, infull.array(), read, nextSize2);
674
+                            read += nextSize2;
675
+                        }
676
+
677
+                        nextSize2 = Math.max(0, Math.min(maxPacketSize, length - read - nextSize - nextSize3));
678
+
679
+                        if (nextSize2 > 0) {
680
+                            bigIn2.position(0);
681
+                            r2.queue(bigIn2, nextSize2);
682
+                        }
683
+
684
+                        if (nextSize3 > 0) {
685
+                            connection.requestWait();
686
+                            System.arraycopy(bigIn3.array(), 0, infull.array(), read, nextSize3);
687
+                            read += nextSize3;
688
+                        }
689
+                    }
690
+                } else {
691
+                    infull = in;
692
+                }
693
+
694
+                infull.position(0);
695
+                try {
696
+                    command.receivedRead(infull);
697
+                    infull = null;
698
+                } catch (RuntimeException e) {
699
+                    // TODO user could send us some data here
700
+                    if (AppConfig.LOG) {
701
+                        Log.e(TAG, "Exception " + e.getLocalizedMessage());
702
+                        e.printStackTrace();
703
+                    }
704
+                    onPtpError(String.format("Error parsing %s with length %d", command.getClass().getSimpleName(),
705
+                            length));
706
+                }
707
+            }
708
+        }
709
+
710
+        private void notifyWorkStarted() {
711
+            WorkerListener l = workerListener;
712
+            if (l != null) {
713
+                l.onWorkerStarted();
714
+            }
715
+        }
716
+
717
+        private void notifyWorkEnded() {
718
+            WorkerListener l = workerListener;
719
+            if (l != null) {
720
+                l.onWorkerEnded();
721
+            }
722
+        }
723
+    }
724
+
725
+    protected void openSession() {
726
+        queue.add(new OpenSessionCommand(this));
727
+    }
728
+
729
+    protected void closeSession() {
730
+        queue.add(new CloseSessionCommand(this));
731
+    }
732
+
733
+    @Override
734
+    public void setWorkerListener(WorkerListener listener) {
735
+        workerListener = listener;
736
+    }
737
+
738
+    @Override
739
+    public String getDeviceName() {
740
+        return deviceInfo != null ? deviceInfo.model : "";
741
+    }
742
+
743
+    @Override
744
+    public boolean isSessionOpen() {
745
+        return state == State.Active;
746
+    }
747
+
748
+    @Override
749
+    public int getProperty(final int property) {
750
+        if (properties.containsKey(property)) {
751
+            return properties.get(property);
752
+        }
753
+        return 0x7fffffff;
754
+    }
755
+
756
+    @Override
757
+    public boolean getPropertyEnabledState(int property) {
758
+        // TODO Auto-generated method stub
759
+        return false;
760
+    }
761
+
762
+    @Override
763
+    public int[] getPropertyDesc(int property) {
764
+        if (propertyDescriptions.containsKey(property)) {
765
+            return propertyDescriptions.get(property);
766
+        }
767
+        return new int[0];
768
+    }
769
+
770
+    @Override
771
+    public void setProperty(int property, int value) {
772
+        final Integer ptpProperty = virtualToPtpProperty.get(property);
773
+        if (ptpProperty != null && ptpPropertyDesc.containsKey(ptpProperty)) {
774
+            queue.add(new SetDevicePropValueCommand(this, ptpProperty, value, ptpPropertyDesc.get(ptpProperty).datatype));
775
+        }
776
+    }
777
+
778
+    @Override
779
+    public String propertyToString(int property, int value) {
780
+        Integer ptpProperty = virtualToPtpProperty.get(property);
781
+        if (ptpProperty != null) {
782
+            String text = PtpPropertyHelper.mapToString(productId, ptpProperty, value);
783
+            return text != null ? text : "?";
784
+        } else {
785
+            return "";
786
+        }
787
+    }
788
+
789
+    @Override
790
+    public Integer propertyToIcon(int property, int value) {
791
+        Integer ptpProperty = virtualToPtpProperty.get(property);
792
+        if (ptpProperty != null) {
793
+            Integer iconId = PtpPropertyHelper.mapToDrawable(ptpProperty, value);
794
+            return iconId != null ? iconId : null;
795
+        } else {
796
+            return null;
797
+        }
798
+    }
799
+
800
+    @Override
801
+    public String getBiggestPropertyValue(int property) {
802
+        Integer ptpProperty = virtualToPtpProperty.get(property);
803
+        if (ptpProperty != null) {
804
+            return PtpPropertyHelper.getBiggestValue(ptpProperty);
805
+        } else {
806
+            return "";
807
+        }
808
+    }
809
+
810
+    @Override
811
+    public void capture() {
812
+        queue.add(new InitiateCaptureCommand(this));
813
+    }
814
+
815
+    @Override
816
+    public boolean isAutoFocusSupported() {
817
+        return autoFocusSupported;
818
+    }
819
+
820
+    @Override
821
+    public boolean isLiveViewSupported() {
822
+        return liveViewSupported;
823
+    }
824
+
825
+    @Override
826
+    public boolean isLiveViewAfAreaSupported() {
827
+        return liveViewAfAreaSupported;
828
+    }
829
+
830
+    @Override
831
+    public boolean isHistogramSupported() {
832
+        return histogramSupported;
833
+    }
834
+
835
+    @Override
836
+    public boolean isLiveViewOpen() {
837
+        return liveViewOpen;
838
+    }
839
+
840
+    @Override
841
+    public boolean isDriveLensSupported() {
842
+        return driveLensSupported;
843
+    }
844
+
845
+    @Override
846
+    public String getDeviceInfo() {
847
+        return deviceInfo != null ? deviceInfo.toString() : "unknown";
848
+    }
849
+
850
+    @Override
851
+    public void writeDebugInfo(File out) {
852
+        try {
853
+            FileWriter writer = new FileWriter(out);
854
+            writer.append(deviceInfo.toString());
855
+            writer.close();
856
+        } catch (IOException e) {
857
+        }
858
+    }
859
+
860
+    @Override
861
+    public void retrievePicture(int objectHandle) {
862
+        queue.add(new RetrievePictureAction(this, objectHandle, pictureSampleSize));
863
+    }
864
+
865
+    @Override
866
+    public void retrieveStorages(StorageInfoListener listener) {
867
+        queue.add(new GetStorageInfosAction(this, listener));
868
+    }
869
+
870
+    @Override
871
+    public void retrieveImageHandles(StorageInfoListener listener, int storageId, int objectFormat) {
872
+        queue.add(new GetObjectHandlesCommand(this, listener, storageId, objectFormat));
873
+    }
874
+
875
+    @Override
876
+    public void retrieveImageInfo(RetrieveImageInfoListener listener, int objectHandle) {
877
+        queue.add(new RetrieveImageInfoAction(this, listener, objectHandle));
878
+    }
879
+
880
+    @Override
881
+    public void retrieveImage(RetrieveImageListener listener, int objectHandle) {
882
+        queue.add(new RetrieveImageAction(this, listener, objectHandle, pictureSampleSize));
883
+    }
884
+
885
+    @Override
886
+    public void setCapturedPictureSampleSize(int sampleSize) {
887
+        this.pictureSampleSize = sampleSize;
888
+    }
889
+
890
+}

+ 496 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpConstants.java

@@ -0,0 +1,496 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.io.BufferedReader;
19
+import java.io.BufferedWriter;
20
+import java.io.IOException;
21
+import java.io.InputStreamReader;
22
+import java.io.OutputStreamWriter;
23
+import java.lang.reflect.Field;
24
+import java.lang.reflect.Modifier;
25
+
26
+public class PtpConstants {
27
+
28
+    public static final int CanonVendorId = 0x04a9;
29
+    public static final int NikonVendorId = 0x04b0;
30
+
31
+    public static boolean isCompatibleVendor(int vendorId) {
32
+        return vendorId == CanonVendorId || vendorId == NikonVendorId;
33
+    }
34
+
35
+    public static class Product {
36
+        // TODO D60 seems not to have a unique id
37
+        //public static final int NikonD700 = 0x041A; // Same as D300?
38
+        public static final int NikonD300 = 0x041A;
39
+        public static final int NikonD300S = 0x0425;
40
+        public static final int NikonD5000 = 0x0423;
41
+        public static final int NikonD5100 = 0x0429;
42
+        public static final int NikonD7000 = 0x0428;
43
+        public static final int NikonD80 = 0x0412;
44
+        public static final int NikonD200 = 0x0410;
45
+        public static final int NikonD3 = 0x041C;
46
+        public static final int NikonD3S = 0x0426;
47
+        public static final int NikonD3X = 0x0420;
48
+        public static final int NikonD40 = 0x0414;
49
+        public static final int NikonD90 = 0x0421;
50
+        public static final int NikonD700 = 0x0422;
51
+    }
52
+
53
+    public static class Type {
54
+        public static final int Undefined = 0;
55
+        public static final int Command = 1;
56
+        public static final int Data = 2;
57
+        public static final int Response = 3;
58
+        public static final int Event = 4;
59
+    }
60
+
61
+    public static String typeToString(int type) {
62
+        return constantToString(Type.class, type);
63
+    }
64
+
65
+    public static class Operation {
66
+        public static final int UndefinedOperationCode = 0x1000;
67
+        public static final int GetDeviceInfo = 0x1001;
68
+        public static final int OpenSession = 0x1002;
69
+        public static final int CloseSession = 0x1003;
70
+        public static final int GetStorageIDs = 0x1004;
71
+        public static final int GetStorageInfo = 0x1005;
72
+        public static final int GetNumObjects = 0x1006;
73
+        public static final int GetObjectHandles = 0x1007;
74
+        public static final int GetObjectInfo = 0x1008;
75
+        public static final int GetObject = 0x1009;
76
+        public static final int GetThumb = 0x100A;
77
+        public static final int DeleteObject = 0x100B;
78
+        public static final int SendObjectInfo = 0x100C;
79
+        public static final int SendObject = 0x100D;
80
+        public static final int InitiateCapture = 0x100E;
81
+        public static final int FormatStore = 0x100F;
82
+        public static final int ResetDevice = 0x1010;
83
+        public static final int SelfTest = 0x1011;
84
+        public static final int SetObjectProtection = 0x1012;
85
+        public static final int PowerDown = 0x1013;
86
+        public static final int GetDevicePropDesc = 0x1014;
87
+        public static final int GetDevicePropValue = 0x1015;
88
+        public static final int SetDevicePropValue = 0x1016;
89
+        public static final int ResetDevicePropValue = 0x1017;
90
+        public static final int TerminateOpenCapture = 0x1018;
91
+        public static final int MoveObject = 0x1019;
92
+        public static final int CopyObject = 0x101A;
93
+        public static final int GetPartialObject = 0x101B;
94
+        public static final int InitiateOpenCapture = 0x101C;
95
+
96
+        public static final int NikonInitiateCaptureRecInSdram = 0x90C0;
97
+        public static final int NikonAfDrive = 0x90C1;
98
+        public static final int NikonChangeCameraMode = 0x90C2;
99
+        public static final int NikonDeleteImagesInSdram = 0x90C3;
100
+        public static final int NikonGetLargeThumb = 0x90C4;
101
+        public static final int NikonGetEvent = 0x90C7;
102
+        public static final int NikonDeviceReady = 0x90C8;
103
+        public static final int NikonSetPreWbData = 0x90C9;
104
+        public static final int NikonGetVendorPropCodes = 0x90CA;
105
+        public static final int NikonAfAndCaptureInSdram = 0x90CB;
106
+        public static final int NikonGetPicCtrlData = 0x90CC;
107
+        public static final int NikonSetPicCtrlData = 0x90CD;
108
+        public static final int NikonDeleteCustomPicCtrl = 0x90CE;
109
+        public static final int NikonGetPicCtrlCapability = 0x90CF;
110
+        public static final int NikonGetPreviewImage = 0x9200;
111
+        public static final int NikonStartLiveView = 0x9201;
112
+        public static final int NikonEndLiveView = 0x9202;
113
+        public static final int NikonGetLiveViewImage = 0x9203;
114
+        public static final int NikonMfDrive = 0x9204;
115
+        public static final int NikonChangeAfArea = 0x9205;
116
+        public static final int NikonAfDriveCancel = 0x9206;
117
+        public static final int NikonInitiateCaptureRecInMedia = 0x9207;
118
+        public static final int NikonGetObjectPropsSupported = 0x9801;
119
+        public static final int NikonGetObjectPropDesc = 0x9802;
120
+        public static final int NikonGetObjectPropValue = 0x9803;
121
+        public static final int NikonGetObjectPropList = 0x9805;
122
+
123
+        // Canon EOS
124
+        public static final int EosTakePicture = 0x910F;
125
+        public static final int EosSetDevicePropValue = 0x9110;
126
+        public static final int EosSetPCConnectMode = 0x9114;
127
+        public static final int EosSetEventMode = 0x9115;
128
+        public static final int EosEventCheck = 0x9116;
129
+        public static final int EosTransferComplete = 0x9117;
130
+        public static final int EosResetTransfer = 0x9119;
131
+        public static final int EosBulbStart = 0x9125;
132
+        public static final int EosBulbEnd = 0x9126;
133
+        public static final int EosGetDevicePropValue = 0x9127;
134
+        public static final int EosRemoteReleaseOn = 0x9128;
135
+        public static final int EosRemoteReleaseOff = 0x9129;
136
+        public static final int EosGetLiveViewPicture = 0x9153;
137
+        public static final int EosDriveLens = 0x9155;
138
+    }
139
+
140
+    public static String operationToString(int operation) {
141
+        return constantToString(Operation.class, operation);
142
+    }
143
+
144
+    public static class Event {
145
+        public static final int CancelTransaction = 0x4001;
146
+        public static final int ObjectAdded = 0x4002;
147
+        public static final int ObjectRemoved = 0x4003;
148
+        public static final int StoreAdded = 0x4004;
149
+        public static final int StoreRemoved = 0x4005;
150
+        public static final int DevicePropChanged = 0x4006;
151
+        public static final int ObjectInfoChanged = 0x4007;
152
+        public static final int DeviceInfoChanged = 0x4008;
153
+        public static final int RequestObjectTransfer = 0x4009;
154
+        public static final int StoreFull = 0x400A;
155
+        public static final int StorageInfoChanged = 0x400C;
156
+        public static final int CaptureComplete = 0x400D;
157
+
158
+        // Nikon
159
+        public static final int NikonObjectAddedInSdram = 0xC101;
160
+        public static final int NikonCaptureCompleteRecInSdram = 0xC102;
161
+        public static final int NikonPreviewImageAdded = 0xC104;
162
+
163
+        // Canon EOS
164
+        public static final int EosObjectAdded = 0xC181; // ? dir item request transfer or dir item created
165
+        public static final int EosDevicePropChanged = 0xC189;
166
+        public static final int EosDevicePropDescChanged = 0xC18A;
167
+        public static final int EosCameraStatus = 0xC18B;
168
+        public static final int EosWillSoonShutdown = 0xC18D;
169
+        public static final int EosBulbExposureTime = 0xc194;
170
+
171
+    }
172
+
173
+    public static String eventToString(int event) {
174
+        return constantToString(Event.class, event);
175
+    }
176
+
177
+    public static class Response {
178
+        public static final int Ok = 0x2001;
179
+        public static final int GeneralError = 0x2002;
180
+        public static final int SessionNotOpen = 0x2003;
181
+        public static final int InvalidTransactionID = 0x2004;
182
+        public static final int OperationNotSupported = 0x2005;
183
+        public static final int ParameterNotSupported = 0x2006;
184
+        public static final int IncompleteTransfer = 0x2007;
185
+        public static final int InvalidStorageID = 0x2008;
186
+        public static final int InvalidObjectHandle = 0x2009;
187
+        public static final int DevicePropNotSupported = 0x200A;
188
+        public static final int InvalidObjectFormatCode = 0x200B;
189
+        public static final int StoreIsFull = 0x200C;
190
+        public static final int ObjectWriteProtect = 0x200D;
191
+        public static final int StoreReadOnly = 0x200E;
192
+        public static final int AccessDenied = 0x200F;
193
+        public static final int NoThumbnailPresent = 0x2010;
194
+        public static final int PartialDeletion = 0x2012;
195
+        public static final int StoreNotAvailable = 0x2013;
196
+        public static final int SpecificationByFormatUnsupported = 0x2014;
197
+        public static final int NoValidObjectInfo = 0x2015;
198
+        public static final int DeviceBusy = 0x2019;
199
+        public static final int InvalidParentObject = 0x201A;
200
+        public static final int InvalidDevicePropFormat = 0x201B;
201
+        public static final int InvalidDevicePropValue = 0x201C;
202
+        public static final int InvalidParameter = 0x201D;
203
+        public static final int SessionAlreadyOpen = 0x201E;
204
+        public static final int TransferCancelled = 0x201F;
205
+        public static final int SpecificationOfDestinationUnsupported = 0x2020;
206
+
207
+        // Nikon ?
208
+        public static final int HardwareError = 0xA001;
209
+        public static final int OutOfFocus = 0xA002;
210
+        public static final int ChangeCameraModeFailed = 0xA003;
211
+        public static final int InvalidStatus = 0xA004;
212
+        public static final int SetPropertyNotSupport = 0xA005;
213
+        public static final int WbPresetError = 0xA006;
214
+        public static final int DustReferenceError = 0xA007;
215
+        public static final int ShutterSpeedBulb = 0xA008;
216
+        public static final int MirrorUpSequence = 0xA009;
217
+        public static final int CameraModeNotAdjustFnumber = 0xA00A;
218
+        public static final int NotLiveView = 0xA00B;
219
+        public static final int MfDriveStepEnd = 0xA00C;
220
+        public static final int MfDriveStepInsufficiency = 0xA00E;
221
+        public static final int InvalidObjectPropCode = 0xA801;
222
+        public static final int InvalidObjectPropFormat = 0xA802;
223
+        public static final int ObjectPropNotSupported = 0xA80A;
224
+
225
+        // Canon EOS
226
+        public static final int EosUnknown_MirrorUp = 0xA102; // ?
227
+    }
228
+
229
+    public static String responseToString(int response) {
230
+        return constantToString(Response.class, response);
231
+    }
232
+
233
+    public static class ObjectFormat {
234
+        public static final int UnknownNonImageObject = 0x3000;
235
+        public static final int Association = 0x3001;
236
+        public static final int Script = 0x3002;
237
+        public static final int Executable = 0x3003;
238
+        public static final int Text = 0x3004;
239
+        public static final int HTML = 0x3005;
240
+        public static final int DPOF = 0x3006;
241
+        public static final int AIFF = 0x3007;
242
+        public static final int WAV = 0x3008;
243
+        public static final int MP3 = 0x3009;
244
+        public static final int AVI = 0x300A;
245
+        public static final int MPEG = 0x300B;
246
+        public static final int ASF = 0x300C;
247
+        public static final int UnknownImageObject = 0x3800;
248
+        public static final int EXIF_JPEG = 0x3801;
249
+        public static final int TIFF_EP = 0x3802;
250
+        public static final int FlashPix = 0x3803;
251
+        public static final int BMP = 0x3804;
252
+        public static final int CIFF = 0x3805;
253
+        public static final int Undefined_Reserved1 = 0x3806;
254
+        public static final int GIF = 0x3807;
255
+        public static final int JFIF = 0x3808;
256
+        public static final int PCD = 0x3809;
257
+        public static final int PICT = 0x380A;
258
+        public static final int PNG = 0x380B;
259
+        public static final int Undefined_Reserved2 = 0x380C;
260
+        public static final int TIFF = 0x380D;
261
+        public static final int TIFF_IT = 0x380E;
262
+        public static final int JP2 = 0x380F;
263
+        public static final int JPX = 0x3810;
264
+
265
+        // Canon
266
+        public static final int EosCRW = 0xb101;
267
+        public static final int EosCRW3 = 0xb103;
268
+        public static final int EosMOV = 0xb104;
269
+    }
270
+
271
+    public static String objectFormatToString(int objectFormat) {
272
+        return constantToString(ObjectFormat.class, objectFormat);
273
+    }
274
+
275
+    public static class Property {
276
+        // PTP
277
+        public static final int UndefinedProperty = 0x5000;
278
+        public static final int BatteryLevel = 0x5001;
279
+        public static final int FunctionalMode = 0x5002;
280
+        public static final int ImageSize = 0x5003;
281
+        public static final int CompressionSetting = 0x5004;
282
+        public static final int WhiteBalance = 0x5005;
283
+        public static final int RGBGain = 0x5006;
284
+        public static final int FNumber = 0x5007; // Aperture Value
285
+        public static final int FocalLength = 0x5008;
286
+        public static final int FocusDistance = 0x5009;
287
+        public static final int FocusMode = 0x500A;
288
+        public static final int ExposureMeteringMode = 0x500B;
289
+        public static final int FlashMode = 0x500C;
290
+        public static final int ExposureTime = 0x500D; // Shutter Speed
291
+        public static final int ExposureProgramMode = 0x500E;
292
+        public static final int ExposureIndex = 0x500F; // ISO Speed
293
+        public static final int ExposureBiasCompensation = 0x5010;
294
+        public static final int DateTime = 0x5011;
295
+        public static final int CaptureDelay = 0x5012;
296
+        public static final int StillCaptureMode = 0x5013;
297
+        public static final int Contrast = 0x5014;
298
+        public static final int Sharpness = 0x5015;
299
+        public static final int DigitalZoom = 0x5016;
300
+        public static final int EffectMode = 0x5017;
301
+        public static final int BurstNumber = 0x5018;
302
+        public static final int BurstInterval = 0x5019;
303
+        public static final int TimelapseNumber = 0x501A;
304
+        public static final int TimelapseInterval = 0x501B;
305
+        public static final int FocusMeteringMode = 0x501C;
306
+        public static final int UploadURL = 0x501D;
307
+        public static final int Artist = 0x501E;
308
+        public static final int CopyrightInfo = 0x501F;
309
+
310
+        // MTP/Microsoft
311
+        public static final int MtpDeviceFriendlyName = 0xD402;
312
+        public static final int MtpSessionInitiatorInfo = 0xD406;
313
+        public static final int MtpPerceivedDeviceType = 0xD407;
314
+
315
+        // Canon EOS
316
+        public static final int EosApertureValue = 0xD101;
317
+        public static final int EosShutterSpeed = 0xD102;
318
+        public static final int EosIsoSpeed = 0xD103;
319
+        public static final int EosExposureCompensation = 0xD104;
320
+        public static final int EosShootingMode = 0xD105;
321
+        public static final int EosDriveMode = 0xD106;
322
+        public static final int EosMeteringMode = 0xD107;
323
+        public static final int EosAfMode = 0xD108;
324
+        public static final int EosWhitebalance = 0xD109;
325
+        public static final int EosColorTemperature = 0xD10A;
326
+        public static final int EosPictureStyle = 0xD110;
327
+        public static final int EosAvailableShots = 0xD11B;
328
+        public static final int EosEvfOutputDevice = 0xD1B0;
329
+        public static final int EosEvfMode = 0xD1B3;
330
+        public static final int EosEvfWhitebalance = 0xD1B4;
331
+        public static final int EosEvfColorTemperature = 0xD1B6;
332
+
333
+        // Nikon
334
+        public static final int NikonShutterSpeed = 0xD100;
335
+        public static final int NikonFocusArea = 0xD108;
336
+        public static final int NikonWbColorTemp = 0xD01E;
337
+        public static final int NikonRecordingMedia = 0xD10B;
338
+        public static final int NikonExposureIndicateStatus = 0xD1B1;
339
+        public static final int NikonActivePicCtrlItem = 0xD200;
340
+        public static final int NikonEnableAfAreaPoint = 0xD08D;
341
+    }
342
+
343
+    public static String propertyToString(int property) {
344
+        return constantToString(Property.class, property);
345
+    }
346
+
347
+    public static class Datatype {
348
+        public static final int int8 = 0x0001;
349
+        public static final int uint8 = 0x002;
350
+        public static final int int16 = 0x003;
351
+        public static final int uint16 = 0x004;
352
+        public static final int int32 = 0x005;
353
+        public static final int uint32 = 0x006;
354
+        public static final int int64 = 0x007;
355
+        public static final int uint64 = 0x008;
356
+        public static final int int128 = 0x009;
357
+        public static final int uint128 = 0x00A;
358
+        public static final int aint8 = 0x4001;
359
+        public static final int auint8 = 0x4002;
360
+        public static final int aint16 = 0x4003;
361
+        public static final int auInt16 = 0x4004;
362
+        public static final int aint32 = 0x4005;
363
+        public static final int auint32 = 0x4006;
364
+        public static final int aint64 = 0x4007;
365
+        public static final int auint64 = 0x4008;
366
+        public static final int aint128 = 0x4009;
367
+        public static final int auint128 = 0x400A;
368
+        public static final int string = 0x00;
369
+    }
370
+
371
+    public static String datatypetoString(int datatype) {
372
+        return constantToString(Datatype.class, datatype);
373
+    }
374
+
375
+    public static int getDatatypeSize(int datatype) {
376
+        switch (datatype) {
377
+        case Datatype.int8:
378
+        case Datatype.uint8:
379
+            return 1;
380
+        case Datatype.int16:
381
+        case Datatype.uint16:
382
+            return 2;
383
+        case Datatype.int32:
384
+        case Datatype.uint32:
385
+            return 4;
386
+        case Datatype.int64:
387
+        case Datatype.uint64:
388
+            return 8;
389
+        default:
390
+            throw new UnsupportedOperationException();
391
+        }
392
+    }
393
+
394
+    /**
395
+     * Returns a string representation of the code field an PTP packet.
396
+     */
397
+    public static String codeToString(int type, int code) {
398
+        switch (type) {
399
+        case Type.Command:
400
+        case Type.Data:
401
+            return operationToString(code);
402
+        case Type.Response:
403
+            return responseToString(code);
404
+        case Type.Event:
405
+            return eventToString(code);
406
+        default:
407
+            return String.format("0x%04x", code);
408
+        }
409
+    }
410
+
411
+    /**
412
+     * Returns the name of the constant that has the specified {@code constant}
413
+     * in the specified {@code clazz}.
414
+     */
415
+    public static String constantToString(Class<?> clazz, int constant) {
416
+        String hexString = String.format("0x%04x", constant);
417
+        for (Field f : clazz.getDeclaredFields()) {
418
+            if (f.getType() != int.class || !Modifier.isStatic(f.getModifiers()) || !Modifier.isFinal(f.getModifiers())) {
419
+                continue;
420
+            }
421
+            try {
422
+                if (f.getInt(null) == constant) {
423
+                    return f.getName() + "(" + hexString + ")";
424
+                }
425
+            } catch (Throwable e) {
426
+                // nop
427
+                e.printStackTrace();
428
+            }
429
+        }
430
+        return hexString;
431
+    }
432
+
433
+    /**
434
+     * Reads {@code DeviceInfo.toString} from input and rewrites codes to
435
+     * names(codes).
436
+     *
437
+     * @throws IOException
438
+     */
439
+    public static void main(String[] args) throws IOException {
440
+        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
441
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
442
+        String line = null;
443
+        int state = 0;
444
+
445
+        while ((line = reader.readLine()) != null) {
446
+            if ("OperationsSupported:".equals(line)) {
447
+                state = 1;
448
+                writer.write(line);
449
+            } else if ("EventsSupported:".equals(line)) {
450
+                state = 2;
451
+                writer.write(line);
452
+            } else if ("DevicePropertiesSupported:".equals(line)) {
453
+                state = 3;
454
+                writer.write(line);
455
+            } else if ("CaptureFormats:".equals(line)) {
456
+                state = 4;
457
+                writer.write(line);
458
+            } else if ("ImageFormats:".equals(line)) {
459
+                state = 5;
460
+                writer.write(line);
461
+            } else {
462
+                if (line.startsWith("    0x") || line.matches("    .+\\)$")) {
463
+                    if (line.startsWith("    0x")) {
464
+                        line = line.trim().substring(2);
465
+                    } else {
466
+                        int bracket = line.indexOf('(');
467
+                        line = line.substring(bracket + 3, line.length() - 1);
468
+                    }
469
+                    int number = Integer.parseInt(line, 16);
470
+                    String value = null;
471
+                    switch (state) {
472
+                    case 1:
473
+                        value = operationToString(number);
474
+                        break;
475
+                    case 2:
476
+                        value = eventToString(number);
477
+                        break;
478
+                    case 3:
479
+                        value = propertyToString(number);
480
+                        break;
481
+                    case 4:
482
+                    case 5:
483
+                        value = objectFormatToString(number);
484
+                        break;
485
+                    }
486
+                    writer.write(String.format("    %s", value));
487
+                } else {
488
+                    writer.write(line);
489
+                }
490
+            }
491
+             writer.newLine();
492
+        }
493
+
494
+        writer.flush();
495
+    }
496
+}

+ 803 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpPropertyHelper.java

@@ -0,0 +1,803 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import com.remoteyourcam.usb.ptp.PtpConstants.Product;
19
+import com.remoteyourcam.usb.ptp.PtpConstants.Property;
20
+
21
+import java.util.HashMap;
22
+import java.util.Map;
23
+
24
+/**
25
+ * Helper to convert property values to their string representations.
26
+ */
27
+public class PtpPropertyHelper {
28
+
29
+    public static final int EOS_SHUTTER_SPEED_BULB = 0x0c;
30
+
31
+    private static final Map<Integer, String> eosShutterSpeedMap = new HashMap<Integer, String>();
32
+    private static final Map<Integer, String> eosApertureValueMap = new HashMap<Integer, String>();
33
+    private static final Map<Integer, String> eosIsoSpeedMap = new HashMap<Integer, String>();
34
+    private static final Map<Integer, String> eosWhitebalanceMap = new HashMap<Integer, String>();
35
+    private static final Map<Integer, Integer> eosWhitebalanceIconsMap = new HashMap<Integer, Integer>();
36
+    private static final Map<Integer, String> eosShootingModeMap = new HashMap<Integer, String>();
37
+    private static final Map<Integer, Integer> eosShootingModeIconsMap = new HashMap<Integer, Integer>();
38
+    private static final Map<Integer, Integer> eosMeteringModeIconsMap = new HashMap<Integer, Integer>();
39
+    private static final Map<Integer, String> eosDriveModeMap = new HashMap<Integer, String>();
40
+    private static final Map<Integer, Integer> eosDriveModeIconsMap = new HashMap<Integer, Integer>();
41
+    private static final Map<Integer, String> eosFocusModeMap = new HashMap<Integer, String>();
42
+    private static final Map<Integer, String> eosPictureStyleMap = new HashMap<Integer, String>();
43
+
44
+    private static final Map<Integer, String> nikonWhitebalanceMap = new HashMap<Integer, String>();
45
+    private static final Map<Integer, Integer> nikonWhitebalanceIconsMap = new HashMap<Integer, Integer>();
46
+    private static final Map<Integer, String> nikonExposureIndexMap = new HashMap<Integer, String>();
47
+    private static final Map<Integer, Integer> nikonExposureProgramMap = new HashMap<Integer, Integer>();
48
+    private static final Map<Integer, String> nikonWbColorTempD300SMap = new HashMap<Integer, String>();
49
+    private static final Map<Integer, String> nikonWbColorTempD200Map = new HashMap<Integer, String>();
50
+    private static final Map<Integer, String> nikonFocusModeMap = new HashMap<Integer, String>();
51
+    private static final Map<Integer, String> nikonActivePicCtrlItemMap = new HashMap<Integer, String>();
52
+    private static final Map<Integer, Integer> nikonMeteringModeMap = new HashMap<Integer, Integer>();
53
+    private static final Map<Integer, String> nikonFocusMeteringModeMap = new HashMap<Integer, String>();
54
+    private static final Map<Integer, Integer> nikonFocusMeteringModeIconsMap = new HashMap<Integer, Integer>();
55
+
56
+    public static String mapToString(int productId, int property, int value) {
57
+        switch (property) {
58
+        case Property.EosShutterSpeed: {
59
+            String s = eosShutterSpeedMap.get(value);
60
+            return s != null ? s : "?";
61
+        }
62
+        case Property.EosApertureValue: {
63
+            String s = eosApertureValueMap.get(value);
64
+            return "f " + (s != null ? s : '?');
65
+        }
66
+        case Property.EosIsoSpeed:
67
+            return eosIsoSpeedMap.get(value);
68
+        case Property.EosWhitebalance:
69
+            return eosWhitebalanceMap.get(value);
70
+        case Property.EosShootingMode:
71
+            return eosShootingModeMap.get(value);
72
+        case Property.EosDriveMode:
73
+            return eosDriveModeMap.get(value);
74
+        case Property.WhiteBalance:
75
+            return nikonWhitebalanceMap.get(value);
76
+        case Property.FNumber: {
77
+            int major = value / 100;
78
+            int minor = value % 100;
79
+            if (minor == 0) {
80
+                return "f " + major;
81
+            } else if (minor % 10 == 0) {
82
+                return "f " + major + '.' + minor / 10;
83
+            } else {
84
+                return "f " + major + '.' + minor;
85
+            }
86
+        }
87
+        case Property.ExposureTime: {
88
+            if (value == 0xFFFFFFFF) {
89
+                return "Bulb";
90
+            }
91
+            int seconds = value / 10000;
92
+            int rest = value % 10000;
93
+            StringBuilder b = new StringBuilder();
94
+            if (seconds > 0) {
95
+                b.append(seconds).append("\"");
96
+            }
97
+            if (rest > 0) {
98
+                b.append("1/").append(Math.round(1.0 / (rest * 0.0001)));
99
+            }
100
+            return b.toString();
101
+        }
102
+        case Property.ExposureIndex:
103
+            return getNikonExposureIndex(productId, value);
104
+        case Property.EosColorTemperature:
105
+            return Integer.toString(value) + "K";
106
+        case Property.NikonWbColorTemp:
107
+            return getNikonWbColorTemp(productId, value);
108
+        case Property.EosAfMode:
109
+            return eosFocusModeMap.get(value);
110
+        case Property.FocusMode:
111
+            return nikonFocusModeMap.get(value);
112
+        case Property.NikonShutterSpeed: {
113
+            int numerator = value >> 16 & 0xffff;
114
+            int denominator = value & 0xffff;
115
+            if (denominator == 1) {
116
+                return "" + numerator + "\"";
117
+            } else if (numerator == 1) {
118
+                return "1/" + denominator;
119
+            } else if (value == 0xFFFFFFFF) {
120
+                return "Bulb";
121
+            } else if (value == 0xFFFFFFFE) {
122
+                return "Flash";
123
+            } else if (numerator > denominator) {
124
+                return String.format("%.1f\"", numerator / (double) denominator);
125
+            }
126
+            return "" + numerator + "/" + denominator;
127
+        }
128
+        case Property.NikonActivePicCtrlItem:
129
+            return nikonActivePicCtrlItemMap.get(value);
130
+        case Property.FocusMeteringMode:
131
+            return nikonFocusMeteringModeMap.get(value);
132
+        case Property.NikonExposureIndicateStatus:
133
+            return "" + value / 6 + "." + Math.abs(value) % 6 + " EV";
134
+        case Property.EosPictureStyle:
135
+            return eosPictureStyleMap.get(value);
136
+        case Property.EosExposureCompensation: {
137
+            int v;
138
+            char ch;
139
+            if (value > 0x80) {
140
+                v = 0x100 - value;
141
+                ch = '-';
142
+            } else {
143
+                v = value;
144
+                ch = '+';
145
+            }
146
+            if (v == 0) {
147
+                return " 0";
148
+            }
149
+            int first = v / 8;
150
+            int second = v % 8;
151
+            String dec = second == 3 ? "1/3" : second == 4 ? "1/2" : second == 5 ? "2/3" : "";
152
+            if (first > 0) {
153
+                return String.format("%c%d %s", ch, first, dec);
154
+            } else {
155
+                return String.format("%c%s", ch, dec);
156
+            }
157
+        }
158
+        case Property.ExposureBiasCompensation: {
159
+            int dec = Math.round(Math.abs(value) / 100.0f);
160
+            int upper = dec / 10;
161
+            int lower = dec % 10;
162
+            char sign = value >= 0 ? '+' : '-';
163
+            return String.format("%c%d.%d", sign, upper, lower);
164
+        }
165
+        default:
166
+            return "?";
167
+        }
168
+    }
169
+
170
+    private static String getNikonExposureIndex(int productId, int value) {
171
+        switch (productId) {
172
+        case Product.NikonD300:
173
+        case Product.NikonD300S:
174
+        case Product.NikonD5000:
175
+            if (value == 0x0064) {
176
+                return "LO-1";
177
+            } else if (value == 0x007D) {
178
+                return "LO-0.7";
179
+            } else if (value == 0x00A0) {
180
+                return "LO-0.3";
181
+            } else if (value == 0x0FA0) {
182
+                return "Hi-0.3";
183
+            } else if (value == 0x1194) {
184
+                return "Hi-0.5";
185
+            } else if (value == 0x1388) {
186
+                return "Hi-0.7";
187
+            } else if (value == 0x1900) {
188
+                return "Hi-1";
189
+            }
190
+            break;
191
+        case Product.NikonD7000:
192
+            if (value == 0x1F40) {
193
+                return "Hi-0.3";
194
+            } else if (value == 0x2328) {
195
+                return "Hi-0.5";
196
+            } else if (value == 0x2710) {
197
+                return "Hi-0.7";
198
+            } else if (value == 0x3200) {
199
+                return "Hi-1";
200
+            } else if (value == 0x6400) {
201
+                return "Hi-2";
202
+            }
203
+            break;
204
+        case Product.NikonD80:
205
+        case Product.NikonD200:
206
+        case Product.NikonD40:
207
+            if (value == 0x07D0) {
208
+                return "Hi-0.3";
209
+            } else if (value == 0x09C4) {
210
+                return "Hi-0.7";
211
+            } else if (value == 0x0C80) {
212
+                return "Hi-1";
213
+            } else if (value == 0x0898) { // D200 only
214
+                return "Hi-0.5";
215
+            }
216
+            break;
217
+        case Product.NikonD3:
218
+            if (value == 0x0064) {
219
+                return "LO-1";
220
+            } else if (value == 0x007D) {
221
+                return "LO-0.7";
222
+            } else if (value == 0x008C) {
223
+                return "LO-0.5";
224
+            } else if (value == 0x00A0) {
225
+                return "LO-0.3";
226
+            } else if (value == 0x2080) {
227
+                return "Hi-0.3";
228
+            } else if (value == 0x2300) {
229
+                return "Hi-0.5";
230
+            } else if (value == 0x2800) {
231
+                return "Hi-0.7";
232
+            } else if (value == 0x3200) {
233
+                return "Hi-1";
234
+            } else if (value == 0x6400) {
235
+                return "Hi-2";
236
+            }
237
+            break;
238
+        case Product.NikonD3X:
239
+            if (value == 0x0032) {
240
+                return "LO-1";
241
+            } else if (value == 0x003E) {
242
+                return "LO-0.7";
243
+            } else if (value == 0x0046) {
244
+                return "LO-0.5";
245
+            } else if (value == 0x0050) {
246
+                return "LO-0.3";
247
+            } else if (value == 0x07D0) {
248
+                return "Hi-0.3";
249
+            } else if (value == 0x08C0) {
250
+                return "Hi-0.5";
251
+            } else if (value == 0x0A00) {
252
+                return "Hi-0.7";
253
+            } else if (value == 0x0C80) {
254
+                return "Hi-1";
255
+            } else if (value == 0x1900) {
256
+                return "Hi-2";
257
+            }
258
+            break;
259
+        case Product.NikonD3S:
260
+            if (value == 0x0064) {
261
+                return "LO-1";
262
+            } else if (value == 0x007D) {
263
+                return "LO-0.7";
264
+            } else if (value == 0x008C) {
265
+                return "LO-0.5";
266
+            } else if (value == 0x00A0) {
267
+                return "LO-0.3";
268
+            } else if (value == 0x3840) {
269
+                return "Hi-0.3";
270
+            } else if (value == 0x4650) {
271
+                return "Hi-0.5";
272
+            } else if (value == 0x4E20) {
273
+                return "Hi-0.7";
274
+            } else if (value == 0x6400) {
275
+                return "Hi-1";
276
+            } else if (value == 0xC800) {
277
+                return "Hi-2";
278
+            }
279
+            break;
280
+        }
281
+        return nikonExposureIndexMap.get(value);
282
+    }
283
+
284
+    private static String getNikonWbColorTemp(int productId, int value) {
285
+        switch (productId) {
286
+        case Product.NikonD300S:
287
+        case Product.NikonD3:
288
+        case Product.NikonD3S:
289
+        case Product.NikonD3X:
290
+        case Product.NikonD300:
291
+        case Product.NikonD700:
292
+        case Product.NikonD7000:
293
+        case Product.NikonD90:
294
+            return nikonWbColorTempD300SMap.get(value);
295
+        case Product.NikonD200:
296
+        case Product.NikonD80:
297
+            return nikonWbColorTempD200Map.get(value);
298
+            //case Product.NikonD60:
299
+            //case Product.NikonD40:
300
+            //case Product.NikonD5000:
301
+            //    return null;
302
+        }
303
+        return null;
304
+    }
305
+
306
+    public static Integer mapToDrawable(int property, int value) {
307
+//        switch (property) {
308
+//        case Property.EosWhitebalance: {
309
+//            Integer resId = eosWhitebalanceIconsMap.get(value);
310
+//            return resId != null ? resId : R.drawable.whitebalance_unknown;
311
+//        }
312
+//        case Property.EosShootingMode: {
313
+//            Integer resId = eosShootingModeIconsMap.get(value);
314
+//            return resId != null ? resId : R.drawable.shootingmode_unknown;
315
+//        }
316
+//        case Property.EosMeteringMode: {
317
+//            Integer resId = eosMeteringModeIconsMap.get(value);
318
+//            return resId != null ? resId : R.drawable.whitebalance_unknown; //TODO own unknown image
319
+//        }
320
+//        case Property.EosDriveMode: {
321
+//            Integer resId = eosDriveModeIconsMap.get(value);
322
+//            return resId != null ? resId : R.drawable.whitebalance_unknown; //TODO own unknown image
323
+//        }
324
+//        case Property.WhiteBalance: {
325
+//            Integer resId = nikonWhitebalanceIconsMap.get(value);
326
+//            return resId != null ? resId : R.drawable.whitebalance_unknown;
327
+//        }
328
+//        case Property.ExposureProgramMode: {
329
+//            Integer resId = nikonExposureProgramMap.get(value);
330
+//            return resId != null ? resId : R.drawable.whitebalance_unknown;
331
+//        }
332
+//        case Property.ExposureMeteringMode: {
333
+//            Integer resId = nikonMeteringModeMap.get(value);
334
+//            return resId != null ? resId : R.drawable.whitebalance_unknown;
335
+//        }
336
+//        case Property.FocusMeteringMode: {
337
+//            Integer resId = nikonFocusMeteringModeIconsMap.get(value);
338
+//            return resId != null ? resId : R.drawable.whitebalance_unknown;
339
+//        }
340
+//        default:
341
+//            return null;
342
+//        }
343
+        return null;
344
+    }
345
+
346
+    public static String getBiggestValue(int property) {
347
+        switch (property) {
348
+        case Property.EosShutterSpeed:
349
+            return "1/8000";
350
+        case Property.EosApertureValue:
351
+            return "f 9.5";
352
+        case Property.EosIsoSpeed:
353
+            return "102400";
354
+        case Property.FNumber:
355
+            return "33.3"; // ?
356
+        case Property.ExposureTime:
357
+            return "1/10000";
358
+        case Property.ExposureIndex:
359
+            return "LO-0.3";
360
+        default:
361
+            return "";
362
+        }
363
+    }
364
+
365
+    static {
366
+        eosShutterSpeedMap.put(0x0c, "Bulb");
367
+        eosShutterSpeedMap.put(0x10, "30\"");
368
+        eosShutterSpeedMap.put(0x13, "25\"");
369
+        eosShutterSpeedMap.put(0x14, "20\"");
370
+        eosShutterSpeedMap.put(0x15, "20\""); // (1/3)");
371
+        eosShutterSpeedMap.put(0x18, "15\"");
372
+        eosShutterSpeedMap.put(0x1B, "13\"");
373
+        eosShutterSpeedMap.put(0x1C, "10\"");
374
+        eosShutterSpeedMap.put(0x1D, "10\""); // (1/3)");
375
+        eosShutterSpeedMap.put(0x20, "8\"");
376
+        eosShutterSpeedMap.put(0x23, "6\""); // (1/3)");
377
+        eosShutterSpeedMap.put(0x24, "6\"");
378
+        eosShutterSpeedMap.put(0x25, "5\"");
379
+        eosShutterSpeedMap.put(0x28, "4\"");
380
+        eosShutterSpeedMap.put(0x2B, "3\"2");
381
+        eosShutterSpeedMap.put(0x2C, "3\"");
382
+        eosShutterSpeedMap.put(0x2D, "2\"5");
383
+        eosShutterSpeedMap.put(0x25, "5\"");
384
+        eosShutterSpeedMap.put(0x28, "4\"");
385
+        eosShutterSpeedMap.put(0x2B, "3\"2");
386
+        eosShutterSpeedMap.put(0x2C, "3\"");
387
+        eosShutterSpeedMap.put(0x2D, "2\"5");
388
+        eosShutterSpeedMap.put(0x30, "2\"");
389
+        eosShutterSpeedMap.put(0x33, "1\"6");
390
+        eosShutterSpeedMap.put(0x34, "1\"5");
391
+        eosShutterSpeedMap.put(0x35, "1\"3");
392
+        eosShutterSpeedMap.put(0x38, "1");
393
+        eosShutterSpeedMap.put(0x3B, "0\"8");
394
+        eosShutterSpeedMap.put(0x3C, "0\"7");
395
+        eosShutterSpeedMap.put(0x3D, "0\"6");
396
+        eosShutterSpeedMap.put(0x40, "0\"5");
397
+        eosShutterSpeedMap.put(0x43, "0\"4");
398
+        eosShutterSpeedMap.put(0x44, "0\"3");
399
+        eosShutterSpeedMap.put(0x45, "0\"3"); // (1/3)");
400
+        eosShutterSpeedMap.put(0x48, "1/4");
401
+        eosShutterSpeedMap.put(0x4B, "1/5");
402
+        eosShutterSpeedMap.put(0x4C, "1/6");
403
+        eosShutterSpeedMap.put(0x4D, "1/6"); // (1/3)");
404
+        eosShutterSpeedMap.put(0x50, "1/8");
405
+        eosShutterSpeedMap.put(0x53, "1/10"); // (1/3)");
406
+        eosShutterSpeedMap.put(0x54, "1/10");
407
+        eosShutterSpeedMap.put(0x55, "1/13");
408
+        eosShutterSpeedMap.put(0x58, "1/15");
409
+        eosShutterSpeedMap.put(0x5B, "1/20"); // (1/3)");
410
+        eosShutterSpeedMap.put(0x5C, "1/20");
411
+        eosShutterSpeedMap.put(0x5D, "1/25");
412
+        eosShutterSpeedMap.put(0x60, "1/30");
413
+        eosShutterSpeedMap.put(0x63, "1/40");
414
+        eosShutterSpeedMap.put(0x64, "1/45");
415
+        eosShutterSpeedMap.put(0x65, "1/50");
416
+        eosShutterSpeedMap.put(0x68, "1/60");
417
+        eosShutterSpeedMap.put(0x6B, "1/80");
418
+        eosShutterSpeedMap.put(0x6C, "1/90");
419
+        eosShutterSpeedMap.put(0x6D, "1/100");
420
+        eosShutterSpeedMap.put(0x70, "1/125");
421
+        eosShutterSpeedMap.put(0x73, "1/160");
422
+        eosShutterSpeedMap.put(0x74, "1/180");
423
+        eosShutterSpeedMap.put(0x75, "1/200");
424
+        eosShutterSpeedMap.put(0x78, "1/250");
425
+        eosShutterSpeedMap.put(0x7B, "1/320");
426
+        eosShutterSpeedMap.put(0x7C, "1/350");
427
+        eosShutterSpeedMap.put(0x7D, "1/400");
428
+        eosShutterSpeedMap.put(0x80, "1/500");
429
+        eosShutterSpeedMap.put(0x83, "1/640");
430
+        eosShutterSpeedMap.put(0x84, "1/750");
431
+        eosShutterSpeedMap.put(0x85, "1/800");
432
+        eosShutterSpeedMap.put(0x88, "1/1000");
433
+        eosShutterSpeedMap.put(0x8B, "1/1250");
434
+        eosShutterSpeedMap.put(0x8C, "1/1500");
435
+        eosShutterSpeedMap.put(0x8D, "1/1600");
436
+        eosShutterSpeedMap.put(0x90, "1/2000");
437
+        eosShutterSpeedMap.put(0x93, "1/2500");
438
+        eosShutterSpeedMap.put(0x94, "1/3000");
439
+        eosShutterSpeedMap.put(0x95, "1/3200");
440
+        eosShutterSpeedMap.put(0x98, "1/4000");
441
+        eosShutterSpeedMap.put(0x9B, "1/5000");
442
+        eosShutterSpeedMap.put(0x9C, "1/6000");
443
+        eosShutterSpeedMap.put(0x9D, "1/6400");
444
+        eosShutterSpeedMap.put(0xA0, "1/8000");
445
+
446
+        eosApertureValueMap.put(0x08, "1");
447
+        eosApertureValueMap.put(0x0B, "1.1");
448
+        eosApertureValueMap.put(0x0C, "1.2");
449
+        eosApertureValueMap.put(0x0D, "1.2"); // (1/3)");
450
+        eosApertureValueMap.put(0x10, "1.4");
451
+        eosApertureValueMap.put(0x13, "1.6");
452
+        eosApertureValueMap.put(0x14, "1.8");
453
+        eosApertureValueMap.put(0x15, "1.8"); // (1/3)");
454
+        eosApertureValueMap.put(0x18, "2");
455
+        eosApertureValueMap.put(0x1B, "2.2");
456
+        eosApertureValueMap.put(0x1C, "2.5");
457
+        eosApertureValueMap.put(0x1D, "2.5"); // (1/3)");
458
+        eosApertureValueMap.put(0x20, "2.8");
459
+        eosApertureValueMap.put(0x23, "3.2");
460
+        eosApertureValueMap.put(0x24, "3.5");
461
+        eosApertureValueMap.put(0x25, "3.5"); // (1/3)");
462
+        eosApertureValueMap.put(0x28, "4");
463
+        eosApertureValueMap.put(0x2B, "4.5");
464
+        eosApertureValueMap.put(0x2C, "4.5");
465
+        eosApertureValueMap.put(0x2D, "5.0");
466
+        eosApertureValueMap.put(0x30, "5.6");
467
+        eosApertureValueMap.put(0x33, "6.3");
468
+        eosApertureValueMap.put(0x34, "6.7");
469
+        eosApertureValueMap.put(0x35, "7.1");
470
+        eosApertureValueMap.put(0x38, "8");
471
+        eosApertureValueMap.put(0x3B, "9");
472
+        eosApertureValueMap.put(0x3C, "9.5");
473
+        eosApertureValueMap.put(0x3D, "10");
474
+        eosApertureValueMap.put(0x40, "11");
475
+        eosApertureValueMap.put(0x43, "13"); // (1/3)");
476
+        eosApertureValueMap.put(0x44, "13");
477
+        eosApertureValueMap.put(0x45, "14");
478
+        eosApertureValueMap.put(0x48, "16");
479
+        eosApertureValueMap.put(0x4B, "18");
480
+        eosApertureValueMap.put(0x4C, "19");
481
+        eosApertureValueMap.put(0x4D, "20");
482
+        eosApertureValueMap.put(0x50, "22");
483
+        eosApertureValueMap.put(0x53, "25");
484
+        eosApertureValueMap.put(0x54, "27");
485
+        eosApertureValueMap.put(0x55, "29");
486
+        eosApertureValueMap.put(0x58, "32");
487
+        eosApertureValueMap.put(0x5B, "36");
488
+        eosApertureValueMap.put(0x5C, "38");
489
+        eosApertureValueMap.put(0x5D, "40");
490
+        eosApertureValueMap.put(0x60, "45");
491
+        eosApertureValueMap.put(0x63, "51");
492
+        eosApertureValueMap.put(0x64, "54");
493
+        eosApertureValueMap.put(0x65, "57");
494
+        eosApertureValueMap.put(0x68, "64");
495
+        eosApertureValueMap.put(0x6B, "72");
496
+        eosApertureValueMap.put(0x6C, "76");
497
+        eosApertureValueMap.put(0x6D, "80");
498
+        eosApertureValueMap.put(0x70, "91");
499
+
500
+        eosIsoSpeedMap.put(0x00, "Auto");
501
+        eosIsoSpeedMap.put(0x28, "6");
502
+        eosIsoSpeedMap.put(0x30, "12");
503
+        eosIsoSpeedMap.put(0x38, "25");
504
+        eosIsoSpeedMap.put(0x40, "50");
505
+        eosIsoSpeedMap.put(0x48, "100");
506
+        eosIsoSpeedMap.put(0x4b, "125");
507
+        eosIsoSpeedMap.put(0x4d, "160");
508
+        eosIsoSpeedMap.put(0x50, "200");
509
+        eosIsoSpeedMap.put(0x53, "250");
510
+        eosIsoSpeedMap.put(0x55, "320");
511
+        eosIsoSpeedMap.put(0x58, "400");
512
+        eosIsoSpeedMap.put(0x5b, "500");
513
+        eosIsoSpeedMap.put(0x5d, "640");
514
+        eosIsoSpeedMap.put(0x60, "800");
515
+        eosIsoSpeedMap.put(0x63, "1000");
516
+        eosIsoSpeedMap.put(0x65, "1250");
517
+        eosIsoSpeedMap.put(0x68, "1600");
518
+        eosIsoSpeedMap.put(0x6b, "2000");
519
+        eosIsoSpeedMap.put(0x6d, "2500");
520
+        eosIsoSpeedMap.put(0x70, "3200");
521
+        eosIsoSpeedMap.put(0x73, "4000");
522
+        eosIsoSpeedMap.put(0x75, "5000");
523
+        eosIsoSpeedMap.put(0x78, "6400");
524
+        eosIsoSpeedMap.put(0x80, "12800");
525
+        eosIsoSpeedMap.put(0x88, "25600");
526
+        eosIsoSpeedMap.put(0x90, "51200");
527
+        eosIsoSpeedMap.put(0x98, "102400");
528
+
529
+        eosWhitebalanceMap.put(0, "Auto");
530
+        eosWhitebalanceMap.put(1, "Daylight");
531
+        eosWhitebalanceMap.put(2, "Cloudy");
532
+        eosWhitebalanceMap.put(3, "Tungsten");
533
+        eosWhitebalanceMap.put(4, "Fluorescent");
534
+        eosWhitebalanceMap.put(5, "Flash");
535
+        eosWhitebalanceMap.put(6, "Manual 1");
536
+        eosWhitebalanceMap.put(8, "Shade");
537
+        eosWhitebalanceMap.put(9, "Color temperature");
538
+        eosWhitebalanceMap.put(10, "PC-1");
539
+        eosWhitebalanceMap.put(11, "PC-2");
540
+        eosWhitebalanceMap.put(12, "PC-3");
541
+        eosWhitebalanceMap.put(15, "Manual 2");
542
+        eosWhitebalanceMap.put(16, "Manual 3");
543
+        eosWhitebalanceMap.put(18, "Manual 4");
544
+        eosWhitebalanceMap.put(19, "Manual");
545
+        eosWhitebalanceMap.put(20, "PC-4");
546
+        eosWhitebalanceMap.put(21, "PC-5");
547
+
548
+//        eosWhitebalanceIconsMap.put(0, R.drawable.whitebalance_auto);
549
+//        eosWhitebalanceIconsMap.put(1, R.drawable.whitebalance_daylight);
550
+//        eosWhitebalanceIconsMap.put(2, R.drawable.whitebalance_cloudy);
551
+//        eosWhitebalanceIconsMap.put(3, R.drawable.whitebalance_tungsten);
552
+//        eosWhitebalanceIconsMap.put(4, R.drawable.whitebalance_fluorescent);
553
+//        eosWhitebalanceIconsMap.put(5, R.drawable.whitebalance_flash);
554
+//        eosWhitebalanceIconsMap.put(6, R.drawable.whitebalance_manual1);
555
+//        eosWhitebalanceIconsMap.put(8, R.drawable.whitebalance_shade);
556
+//        eosWhitebalanceIconsMap.put(9, R.drawable.whitebalance_color_temperature);
557
+//        eosWhitebalanceIconsMap.put(10, R.drawable.whitebalance_custom1);
558
+//        eosWhitebalanceIconsMap.put(11, R.drawable.whitebalance_custom2);
559
+//        eosWhitebalanceIconsMap.put(12, R.drawable.whitebalance_custom3);
560
+//        eosWhitebalanceIconsMap.put(15, R.drawable.whitebalance_manual2);
561
+//        eosWhitebalanceIconsMap.put(16, R.drawable.whitebalance_manual3);
562
+//        eosWhitebalanceIconsMap.put(18, R.drawable.whitebalance_manual4);
563
+//        eosWhitebalanceIconsMap.put(19, R.drawable.whitebalance_manual5);
564
+//        eosWhitebalanceIconsMap.put(20, R.drawable.whitebalance_custom4);
565
+//        eosWhitebalanceIconsMap.put(21, R.drawable.whitebalance_custom5);
566
+
567
+        eosShootingModeMap.put(0, "Program AE");
568
+        eosShootingModeMap.put(1, "Shutter-Speed Priority AE");
569
+        eosShootingModeMap.put(2, "Aperture Priority AE");
570
+        eosShootingModeMap.put(3, "Manual Exposure");
571
+        eosShootingModeMap.put(4, "Bulb");
572
+        eosShootingModeMap.put(5, "Auto Depth-of-Field AE");
573
+        eosShootingModeMap.put(6, "Depth-of-Field AE");
574
+        eosShootingModeMap.put(8, "Lock");
575
+        eosShootingModeMap.put(9, "Auto");
576
+        eosShootingModeMap.put(10, "Night Scene Portrait");
577
+        eosShootingModeMap.put(11, "Sports");
578
+        eosShootingModeMap.put(12, "Portrait");
579
+        eosShootingModeMap.put(13, "Landscape");
580
+        eosShootingModeMap.put(14, "Close-Up");
581
+        eosShootingModeMap.put(15, "Flash Off");
582
+        eosShootingModeMap.put(19, "Creative Auto");
583
+
584
+//        eosShootingModeIconsMap.put(0, R.drawable.shootingmode_program);
585
+//        eosShootingModeIconsMap.put(1, R.drawable.shootingmode_tv);
586
+//        eosShootingModeIconsMap.put(2, R.drawable.shootingmode_av);
587
+//        eosShootingModeIconsMap.put(3, R.drawable.shootingmode_m);
588
+//        eosShootingModeIconsMap.put(4, R.drawable.shootingmode_bulb);
589
+//        eosShootingModeIconsMap.put(5, R.drawable.shootingmode_adep);
590
+//        eosShootingModeIconsMap.put(6, R.drawable.shootingmode_dep);
591
+//        eosShootingModeIconsMap.put(8, R.drawable.shootingmode_lock);
592
+//        eosShootingModeIconsMap.put(9, R.drawable.shootingmode_auto);
593
+//        eosShootingModeIconsMap.put(10, R.drawable.shootingmode_night_scene_portrait);
594
+//        eosShootingModeIconsMap.put(11, R.drawable.shootingmode_sports);
595
+//        eosShootingModeIconsMap.put(12, R.drawable.shootingmode_portrait);
596
+//        eosShootingModeIconsMap.put(13, R.drawable.shootingmode_landscape);
597
+//        eosShootingModeIconsMap.put(14, R.drawable.shootingmode_close_up);
598
+//        eosShootingModeIconsMap.put(15, R.drawable.shootingmode_flash_off);
599
+//        eosShootingModeIconsMap.put(19, R.drawable.shootingmode_creativeauto);
600
+
601
+        eosDriveModeMap.put(0, "Single Shooting");
602
+        eosDriveModeMap.put(1, "Continuous Shooting");
603
+        eosDriveModeMap.put(2, "Video");
604
+        eosDriveModeMap.put(3, "?");
605
+        eosDriveModeMap.put(4, "High-Speed Continuous Shooting");
606
+        eosDriveModeMap.put(5, "Low-Speed Continuous Shooting");
607
+        eosDriveModeMap.put(6, "Silent Single Shooting");
608
+        eosDriveModeMap.put(7, "10-Sec Self-Timer plus Continuous Shooting");
609
+        eosDriveModeMap.put(0x10, "10-Sec Self-Timer");
610
+        eosDriveModeMap.put(0x11, "2-Sec Self-Timer");
611
+
612
+        // TODO easDriveModeIconsmap
613
+
614
+        eosFocusModeMap.put(0, "One-Shot AF");
615
+        eosFocusModeMap.put(1, "AI Servo AF");
616
+        eosFocusModeMap.put(2, "AI Focus AF");
617
+        eosFocusModeMap.put(3, "Manual Focus");
618
+
619
+        nikonWhitebalanceMap.put(2, "Auto");
620
+        nikonWhitebalanceMap.put(4, "Sunny");
621
+        nikonWhitebalanceMap.put(5, "Fluorescent");
622
+        nikonWhitebalanceMap.put(6, "Incandescent");
623
+        nikonWhitebalanceMap.put(7, "Flash");
624
+        nikonWhitebalanceMap.put(0x8010, "Cloudy");
625
+        nikonWhitebalanceMap.put(0x8011, "Sunny shade");
626
+        nikonWhitebalanceMap.put(0x8012, "Color temperature");
627
+        nikonWhitebalanceMap.put(0x8013, "Preset");
628
+
629
+//        nikonWhitebalanceIconsMap.put(2, R.drawable.whitebalance_auto);
630
+//        nikonWhitebalanceIconsMap.put(4, R.drawable.whitebalance_daylight);
631
+//        nikonWhitebalanceIconsMap.put(5, R.drawable.whitebalance_fluorescent);
632
+//        nikonWhitebalanceIconsMap.put(6, R.drawable.whitebalance_tungsten);
633
+//        nikonWhitebalanceIconsMap.put(7, R.drawable.whitebalance_flash);
634
+//        nikonWhitebalanceIconsMap.put(0x8010, R.drawable.whitebalance_cloudy);
635
+//        nikonWhitebalanceIconsMap.put(0x8011, R.drawable.whitebalance_shade);
636
+//        nikonWhitebalanceIconsMap.put(0x8012, R.drawable.whitebalance_color_temperature);
637
+//        nikonWhitebalanceIconsMap.put(0x8013, R.drawable.whitebalance_custom1); // TODO create Nikon specific icon
638
+
639
+        nikonExposureIndexMap.put(0x0064, "100");
640
+        nikonExposureIndexMap.put(0x007D, "125");
641
+        nikonExposureIndexMap.put(0x00A0, "160");
642
+        nikonExposureIndexMap.put(0x00C8, "200");
643
+        nikonExposureIndexMap.put(0x00FA, "250");
644
+        nikonExposureIndexMap.put(0x0118, "280");
645
+        nikonExposureIndexMap.put(0x0140, "320");
646
+        nikonExposureIndexMap.put(0x0190, "400");
647
+        nikonExposureIndexMap.put(0x01F4, "500");
648
+        nikonExposureIndexMap.put(0x0230, "560");
649
+        nikonExposureIndexMap.put(0x0280, "640");
650
+        nikonExposureIndexMap.put(0x0320, "800");
651
+        nikonExposureIndexMap.put(0x03E8, "1000");
652
+        nikonExposureIndexMap.put(0x044C, "1100");
653
+        nikonExposureIndexMap.put(0x04E2, "1250");
654
+        nikonExposureIndexMap.put(0x0640, "1600");
655
+        nikonExposureIndexMap.put(0x07D0, "2000");
656
+        nikonExposureIndexMap.put(0x0898, "2200");
657
+        nikonExposureIndexMap.put(0x09C4, "2500");
658
+        nikonExposureIndexMap.put(0x0C80, "3200");
659
+        nikonExposureIndexMap.put(0x0FA0, "4000");
660
+        nikonExposureIndexMap.put(0x1194, "4500");
661
+        nikonExposureIndexMap.put(0x1388, "5000");
662
+        nikonExposureIndexMap.put(0x1900, "6400");
663
+        nikonExposureIndexMap.put(0x1F40, "8000");
664
+        nikonExposureIndexMap.put(0x2328, "9000");
665
+        nikonExposureIndexMap.put(0x2710, "10000");
666
+        nikonExposureIndexMap.put(0x3200, "12800");
667
+
668
+//        nikonExposureProgramMap.put(0x0001, R.drawable.shootingmode_m);
669
+//        nikonExposureProgramMap.put(0x0002, R.drawable.shootingmode_program);
670
+//        nikonExposureProgramMap.put(0x0003, R.drawable.shootingmode_av);
671
+//        nikonExposureProgramMap.put(0x0004, R.drawable.shootingmode_tv);
672
+//        nikonExposureProgramMap.put(0x8010, R.drawable.shootingmode_auto);
673
+//        nikonExposureProgramMap.put(0x8011, R.drawable.shootingmode_portrait);
674
+//        nikonExposureProgramMap.put(0x8012, R.drawable.shootingmode_landscape);
675
+//        nikonExposureProgramMap.put(0x8013, R.drawable.shootingmode_close_up);
676
+//        nikonExposureProgramMap.put(0x8014, R.drawable.shootingmode_sports);
677
+//        nikonExposureProgramMap.put(0x8015, R.drawable.shootingmode_night_scene_portrait);
678
+//        nikonExposureProgramMap.put(0x8016, R.drawable.shootingmode_flash_off);
679
+//        nikonExposureProgramMap.put(0x8017, R.drawable.shootingmode_unknown); // TODO Child
680
+//        nikonExposureProgramMap.put(0x8018, R.drawable.shootingmode_unknown); // TODO SCENE
681
+//        nikonExposureProgramMap.put(0x8050, R.drawable.shootingmode_unknown); // TODO User mode U1
682
+//        nikonExposureProgramMap.put(0x8051, R.drawable.shootingmode_unknown); // TODO User mode U2
683
+
684
+        nikonWbColorTempD300SMap.put(0, "2500K");
685
+        nikonWbColorTempD300SMap.put(1, "2560K");
686
+        nikonWbColorTempD300SMap.put(2, "2630K");
687
+        nikonWbColorTempD300SMap.put(3, "2700K");
688
+        nikonWbColorTempD300SMap.put(4, "2780K");
689
+        nikonWbColorTempD300SMap.put(5, "2860K");
690
+        nikonWbColorTempD300SMap.put(6, "2940K");
691
+        nikonWbColorTempD300SMap.put(7, "3030K");
692
+        nikonWbColorTempD300SMap.put(8, "3130K");
693
+        nikonWbColorTempD300SMap.put(9, "3230K");
694
+        nikonWbColorTempD300SMap.put(10, "3330K");
695
+        nikonWbColorTempD300SMap.put(11, "3450K");
696
+        nikonWbColorTempD300SMap.put(12, "3570K");
697
+        nikonWbColorTempD300SMap.put(13, "3700K");
698
+        nikonWbColorTempD300SMap.put(14, "3850K");
699
+        nikonWbColorTempD300SMap.put(15, "4000K");
700
+        nikonWbColorTempD300SMap.put(16, "4170K");
701
+        nikonWbColorTempD300SMap.put(17, "4350K");
702
+        nikonWbColorTempD300SMap.put(18, "4550K");
703
+        nikonWbColorTempD300SMap.put(19, "4760K");
704
+        nikonWbColorTempD300SMap.put(20, "5000K");
705
+        nikonWbColorTempD300SMap.put(21, "5260K");
706
+        nikonWbColorTempD300SMap.put(22, "5560K");
707
+        nikonWbColorTempD300SMap.put(23, "5880K");
708
+        nikonWbColorTempD300SMap.put(24, "6250K");
709
+        nikonWbColorTempD300SMap.put(25, "6670K");
710
+        nikonWbColorTempD300SMap.put(26, "7140K");
711
+        nikonWbColorTempD300SMap.put(27, "7690K");
712
+        nikonWbColorTempD300SMap.put(28, "8330K");
713
+        nikonWbColorTempD300SMap.put(29, "9090K");
714
+        nikonWbColorTempD300SMap.put(30, "10000K");
715
+
716
+        nikonWbColorTempD200Map.put(0, "2500K");
717
+        nikonWbColorTempD200Map.put(1, "2550K");
718
+        nikonWbColorTempD200Map.put(2, "2650K");
719
+        nikonWbColorTempD200Map.put(3, "2700K");
720
+        nikonWbColorTempD200Map.put(4, "2800K");
721
+        nikonWbColorTempD200Map.put(5, "2850K");
722
+        nikonWbColorTempD200Map.put(6, "2950K");
723
+        nikonWbColorTempD200Map.put(7, "3000K");
724
+        nikonWbColorTempD200Map.put(8, "3100K");
725
+        nikonWbColorTempD200Map.put(9, "3200K");
726
+        nikonWbColorTempD200Map.put(10, "3300K");
727
+        nikonWbColorTempD200Map.put(11, "3400K");
728
+        nikonWbColorTempD200Map.put(12, "3600K");
729
+        nikonWbColorTempD200Map.put(13, "3700K");
730
+        nikonWbColorTempD200Map.put(14, "3800K");
731
+        nikonWbColorTempD200Map.put(15, "4000K");
732
+        nikonWbColorTempD200Map.put(16, "4200K");
733
+        nikonWbColorTempD200Map.put(17, "4300K");
734
+        nikonWbColorTempD200Map.put(18, "4500K");
735
+        nikonWbColorTempD200Map.put(19, "4800K");
736
+        nikonWbColorTempD200Map.put(20, "5000K");
737
+        nikonWbColorTempD200Map.put(21, "5300K");
738
+        nikonWbColorTempD200Map.put(22, "5600K");
739
+        nikonWbColorTempD200Map.put(23, "5900K");
740
+        nikonWbColorTempD200Map.put(24, "6300K");
741
+        nikonWbColorTempD200Map.put(25, "6700K");
742
+        nikonWbColorTempD200Map.put(26, "7100K");
743
+        nikonWbColorTempD200Map.put(27, "7700K");
744
+        nikonWbColorTempD200Map.put(28, "8300K");
745
+        nikonWbColorTempD200Map.put(29, "9100K");
746
+        nikonWbColorTempD200Map.put(30, "10000K");
747
+
748
+        nikonFocusModeMap.put(0x0001, "Manual Focus");
749
+        nikonFocusModeMap.put(0x8010, "Single AF servo");
750
+        nikonFocusModeMap.put(0x8011, "Continous AF servo");
751
+        nikonFocusModeMap.put(0x8012, "AF servo auto switch");
752
+        nikonFocusModeMap.put(0x8013, "Constant AF servo");
753
+
754
+        nikonActivePicCtrlItemMap.put(1, "SD");
755
+        nikonActivePicCtrlItemMap.put(2, "NL");
756
+        nikonActivePicCtrlItemMap.put(3, "VI");
757
+        nikonActivePicCtrlItemMap.put(4, "MC");
758
+        nikonActivePicCtrlItemMap.put(5, "PT");
759
+        nikonActivePicCtrlItemMap.put(6, "LS");
760
+        nikonActivePicCtrlItemMap.put(101, "O-1");
761
+        nikonActivePicCtrlItemMap.put(102, "O-2");
762
+        nikonActivePicCtrlItemMap.put(103, "O-3");
763
+        nikonActivePicCtrlItemMap.put(104, "O-4");
764
+        nikonActivePicCtrlItemMap.put(201, "C-1");
765
+        nikonActivePicCtrlItemMap.put(202, "C-2");
766
+        nikonActivePicCtrlItemMap.put(203, "C-3");
767
+        nikonActivePicCtrlItemMap.put(204, "C-4");
768
+        nikonActivePicCtrlItemMap.put(205, "C-5");
769
+        nikonActivePicCtrlItemMap.put(206, "C-6");
770
+        nikonActivePicCtrlItemMap.put(207, "C-7");
771
+        nikonActivePicCtrlItemMap.put(208, "C-8");
772
+        nikonActivePicCtrlItemMap.put(209, "C-9");
773
+
774
+//        nikonMeteringModeMap.put(2, R.drawable.metering_exposure_center_weighted_nikon);
775
+//        nikonMeteringModeMap.put(3, R.drawable.metering_exposure_matrix_nikon);
776
+//        nikonMeteringModeMap.put(4, R.drawable.metering_exposure_spot);
777
+//
778
+//        eosMeteringModeIconsMap.put(1, R.drawable.metering_exposure_spot);
779
+//        eosMeteringModeIconsMap.put(3, R.drawable.metering_exposure_evaluative_canon);
780
+//        eosMeteringModeIconsMap.put(4, R.drawable.metering_exposure_partial);
781
+//        eosMeteringModeIconsMap.put(5, R.drawable.metering_exposure_center_weighted_average_canon);
782
+
783
+        nikonFocusMeteringModeMap.put(0x0002, "Dynamic");
784
+        nikonFocusMeteringModeMap.put(0x8010, "Single point");
785
+        nikonFocusMeteringModeMap.put(0x8011, "Auto area");
786
+        nikonFocusMeteringModeMap.put(0x8012, "3D");
787
+
788
+//        nikonFocusMeteringModeIconsMap.put(0x0002, R.drawable.metering_af_dynamic_area);
789
+//        nikonFocusMeteringModeIconsMap.put(0x8010, R.drawable.metering_af_single_point);
790
+//        nikonFocusMeteringModeIconsMap.put(0x8011, R.drawable.metering_af_auto_area);
791
+//        nikonFocusMeteringModeIconsMap.put(0x8012, R.drawable.metering_af_3d_tracking);
792
+
793
+        eosPictureStyleMap.put(0x81, "ST");
794
+        eosPictureStyleMap.put(0x82, "PT");
795
+        eosPictureStyleMap.put(0x83, "LS");
796
+        eosPictureStyleMap.put(0x84, "NL");
797
+        eosPictureStyleMap.put(0x85, "FL");
798
+        eosPictureStyleMap.put(0x86, "MO");
799
+        eosPictureStyleMap.put(0x21, "UD1");
800
+        eosPictureStyleMap.put(0x22, "UD2");
801
+        eosPictureStyleMap.put(0x23, "UD3");
802
+    }
803
+}

+ 47 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpService.java

@@ -0,0 +1,47 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import com.remoteyourcam.usb.ptp.Camera.CameraListener;
19
+
20
+import android.content.Context;
21
+import android.content.Intent;
22
+
23
+public interface PtpService {
24
+
25
+    void setCameraListener(CameraListener listener);
26
+
27
+    void initialize(Context context, Intent intent);
28
+
29
+    void shutdown();
30
+
31
+    void lazyShutdown();
32
+
33
+    public static class Singleton {
34
+        private static PtpService singleton;
35
+
36
+        public static PtpService getInstance(Context context) {
37
+            if (singleton == null) {
38
+                singleton = new PtpUsbService(context);
39
+            }
40
+            return singleton;
41
+        }
42
+
43
+        public static void setInstance(PtpService service) {
44
+            singleton = service;
45
+        }
46
+    }
47
+}

+ 76 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpUsbConnection.java

@@ -0,0 +1,76 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import android.hardware.usb.UsbDeviceConnection;
19
+import android.hardware.usb.UsbEndpoint;
20
+import android.hardware.usb.UsbRequest;
21
+
22
+public class PtpUsbConnection {
23
+
24
+    private final UsbDeviceConnection connection;
25
+    private final UsbEndpoint bulkOut;
26
+    private final UsbEndpoint bulkIn;
27
+    private final int vendorId;
28
+    private final int productId;
29
+
30
+    public PtpUsbConnection(UsbDeviceConnection connection, UsbEndpoint bulkIn, UsbEndpoint bulkOut, int vendorId,
31
+            int productId) {
32
+        this.connection = connection;
33
+        this.bulkIn = bulkIn;
34
+        this.bulkOut = bulkOut;
35
+        this.vendorId = vendorId;
36
+        this.productId = productId;
37
+    }
38
+
39
+    public int getVendorId() {
40
+        return vendorId;
41
+    }
42
+
43
+    public int getProductId() {
44
+        return productId;
45
+    }
46
+
47
+    public void close() {
48
+        connection.close();
49
+    }
50
+
51
+    public int getMaxPacketInSize() {
52
+        return bulkIn.getMaxPacketSize();
53
+    }
54
+
55
+    public int getMaxPacketOutSize() {
56
+        return bulkOut.getMaxPacketSize();
57
+    }
58
+
59
+    public UsbRequest createInRequest() {
60
+        UsbRequest r = new UsbRequest();
61
+        r.initialize(connection, bulkIn);
62
+        return r;
63
+    }
64
+
65
+    public int bulkTransferOut(byte[] buffer, int length, int timeout) {
66
+        return connection.bulkTransfer(bulkOut, buffer, length, timeout);
67
+    }
68
+
69
+    public int bulkTransferIn(byte[] buffer, int maxLength, int timeout) {
70
+        return connection.bulkTransfer(bulkIn, buffer, maxLength, timeout);
71
+    }
72
+
73
+    public void requestWait() {
74
+        connection.requestWait();
75
+    }
76
+}

+ 228 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/PtpUsbService.java

@@ -0,0 +1,228 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import java.util.Map;
19
+
20
+import android.app.PendingIntent;
21
+import android.content.BroadcastReceiver;
22
+import android.content.Context;
23
+import android.content.Intent;
24
+import android.content.IntentFilter;
25
+import android.hardware.usb.UsbConstants;
26
+import android.hardware.usb.UsbDevice;
27
+import android.hardware.usb.UsbEndpoint;
28
+import android.hardware.usb.UsbInterface;
29
+import android.hardware.usb.UsbManager;
30
+import android.os.Handler;
31
+import android.util.Log;
32
+
33
+import com.remoteyourcam.usb.AppConfig;
34
+import com.remoteyourcam.usb.ptp.Camera.CameraListener;
35
+import com.remoteyourcam.usb.ptp.PtpCamera.State;
36
+
37
+public class PtpUsbService implements PtpService {
38
+
39
+    private final String TAG = PtpUsbService.class.getSimpleName();
40
+
41
+    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
42
+    private final BroadcastReceiver permissonReceiver = new BroadcastReceiver() {
43
+        @Override
44
+        public void onReceive(Context context, Intent intent) {
45
+            String action = intent.getAction();
46
+            if (ACTION_USB_PERMISSION.equals(action)) {
47
+                unregisterPermissionReceiver(context);
48
+                synchronized (this) {
49
+                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
50
+
51
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
52
+                        connect(context, device);
53
+                    } else {
54
+                        //TODO report
55
+                    }
56
+                }
57
+            }
58
+        }
59
+    };
60
+
61
+    private final Handler handler = new Handler();
62
+    private final UsbManager usbManager;
63
+    private PtpCamera camera;
64
+    private CameraListener listener;
65
+
66
+    Runnable shutdownRunnable = new Runnable() {
67
+        @Override
68
+        public void run() {
69
+            shutdown();
70
+        }
71
+    };
72
+
73
+    public PtpUsbService(Context context) {
74
+        this.usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
75
+    }
76
+
77
+    @Override
78
+    public void setCameraListener(CameraListener listener) {
79
+        this.listener = listener;
80
+        if (camera != null) {
81
+            camera.setListener(listener);
82
+        }
83
+    }
84
+
85
+    @Override
86
+    public void initialize(Context context, Intent intent) {
87
+        handler.removeCallbacks(shutdownRunnable);
88
+        if (camera != null) {
89
+            if (AppConfig.LOG) {
90
+                Log.i(TAG, "initialize: camera available");
91
+            }
92
+            if (camera.getState() == State.Active) {
93
+                if (listener != null) {
94
+                    listener.onCameraStarted(camera);
95
+                }
96
+                return;
97
+            }
98
+            if (AppConfig.LOG) {
99
+                Log.i(TAG, "initialize: camera not active, satet " + camera.getState());
100
+            }
101
+            camera.shutdownHard();
102
+        }
103
+        UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
104
+        if (device != null) {
105
+            if (AppConfig.LOG) {
106
+                Log.i(TAG, "initialize: got device through intent");
107
+            }
108
+            connect(context, device);
109
+        } else {
110
+            if (AppConfig.LOG) {
111
+                Log.i(TAG, "initialize: looking for compatible camera");
112
+            }
113
+            device = lookupCompatibleDevice(usbManager);
114
+            if (device != null) {
115
+                registerPermissionReceiver(context);
116
+                PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(
117
+                        ACTION_USB_PERMISSION), 0);
118
+                usbManager.requestPermission(device, mPermissionIntent);
119
+            } else {
120
+                listener.onNoCameraFound();
121
+            }
122
+        }
123
+    }
124
+
125
+    @Override
126
+    public void shutdown() {
127
+        if (AppConfig.LOG) {
128
+            Log.i(TAG, "shutdown");
129
+        }
130
+        if (camera != null) {
131
+            camera.shutdown();
132
+            camera = null;
133
+        }
134
+    }
135
+
136
+    @Override
137
+    public void lazyShutdown() {
138
+        if (AppConfig.LOG) {
139
+            Log.i(TAG, "lazy shutdown");
140
+        }
141
+        handler.postDelayed(shutdownRunnable, 4000);
142
+    }
143
+
144
+    private void registerPermissionReceiver(Context context) {
145
+        if (AppConfig.LOG) {
146
+            Log.i(TAG, "register permission receiver");
147
+        }
148
+        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
149
+        context.registerReceiver(permissonReceiver, filter);
150
+    }
151
+
152
+    private void unregisterPermissionReceiver(Context context) {
153
+        if (AppConfig.LOG) {
154
+            Log.i(TAG, "unregister permission receiver");
155
+        }
156
+        context.unregisterReceiver(permissonReceiver);
157
+    }
158
+
159
+    private UsbDevice lookupCompatibleDevice(UsbManager manager) {
160
+        Map<String, UsbDevice> deviceList = manager.getDeviceList();
161
+        for (Map.Entry<String, UsbDevice> e : deviceList.entrySet()) {
162
+            UsbDevice d = e.getValue();
163
+            if (d.getVendorId() == PtpConstants.CanonVendorId || d.getVendorId() == PtpConstants.NikonVendorId) {
164
+                return d;
165
+            }
166
+        }
167
+        return null;
168
+    }
169
+
170
+    private boolean connect(Context context, UsbDevice device) {
171
+        if (camera != null) {
172
+            camera.shutdown();
173
+            camera = null;
174
+        }
175
+        for (int i = 0, n = device.getInterfaceCount(); i < n; ++i) {
176
+            UsbInterface intf = device.getInterface(i);
177
+
178
+            if (intf.getEndpointCount() != 3) {
179
+                continue;
180
+            }
181
+
182
+            UsbEndpoint in = null;
183
+            UsbEndpoint out = null;
184
+
185
+            for (int e = 0, en = intf.getEndpointCount(); e < en; ++e) {
186
+                UsbEndpoint endpoint = intf.getEndpoint(e);
187
+                if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
188
+                    if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
189
+                        in = endpoint;
190
+                    } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
191
+                        out = endpoint;
192
+                    }
193
+                }
194
+            }
195
+
196
+            if (in == null || out == null) {
197
+                continue;
198
+            }
199
+
200
+            if (AppConfig.LOG) {
201
+                Log.i(TAG, "Found compatible USB interface");
202
+                Log.i(TAG, "Interface class " + intf.getInterfaceClass());
203
+                Log.i(TAG, "Interface subclass " + intf.getInterfaceSubclass());
204
+                Log.i(TAG, "Interface protocol " + intf.getInterfaceProtocol());
205
+                Log.i(TAG, "Bulk out max size " + out.getMaxPacketSize());
206
+                Log.i(TAG, "Bulk in max size " + in.getMaxPacketSize());
207
+            }
208
+
209
+            if (device.getVendorId() == PtpConstants.CanonVendorId) {
210
+                PtpUsbConnection connection = new PtpUsbConnection(usbManager.openDevice(device), in, out,
211
+                        device.getVendorId(), device.getProductId());
212
+                camera = new EosCamera(connection, listener, new WorkerNotifier(context));
213
+            } else if (device.getVendorId() == PtpConstants.NikonVendorId) {
214
+                PtpUsbConnection connection = new PtpUsbConnection(usbManager.openDevice(device), in, out,
215
+                        device.getVendorId(), device.getProductId());
216
+                camera = new NikonCamera(connection, listener, new WorkerNotifier(context));
217
+            }
218
+
219
+            return true;
220
+        }
221
+
222
+        if (listener != null) {
223
+            listener.onError("No compatible camera found");
224
+        }
225
+
226
+        return false;
227
+    }
228
+}

+ 34 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/WorkerNotifier.java

@@ -0,0 +1,34 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp;
17
+
18
+import android.content.Context;
19
+
20
+public class WorkerNotifier implements Camera.WorkerListener {
21
+
22
+
23
+    public WorkerNotifier(Context context) {
24
+    }
25
+
26
+    @Override
27
+    public void onWorkerStarted() {
28
+    }
29
+
30
+    @Override
31
+    public void onWorkerEnded() {
32
+    }
33
+
34
+}

+ 61 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/CloseSessionCommand.java

@@ -0,0 +1,61 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.AppConfig;
21
+import com.remoteyourcam.usb.ptp.PtpCamera;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
25
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
26
+
27
+import android.util.Log;
28
+
29
+public class CloseSessionCommand extends Command {
30
+
31
+    private final String TAG = CloseSessionCommand.class.getSimpleName();
32
+
33
+    public CloseSessionCommand(PtpCamera camera) {
34
+        super(camera);
35
+    }
36
+
37
+    @Override
38
+    public void exec(IO io) {
39
+        io.handleCommand(this);
40
+        // Can this even happen?
41
+        if (responseCode == Response.DeviceBusy) {
42
+            camera.onDeviceBusy(this, true);
43
+            return;
44
+        }
45
+        // close even when error happened
46
+        camera.onSessionClosed();
47
+        if (responseCode != Response.Ok) {
48
+            // TODO error report
49
+            if (AppConfig.LOG) {
50
+                Log.w(TAG,
51
+                        String.format("Error response when closing session, response %s",
52
+                                PtpConstants.responseToString(responseCode)));
53
+            }
54
+        }
55
+    }
56
+
57
+    @Override
58
+    public void encodeCommand(ByteBuffer b) {
59
+        encodeCommand(b, Operation.CloseSession);
60
+    }
61
+}

+ 188 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/Command.java

@@ -0,0 +1,188 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import android.util.Log;
19
+
20
+import com.remoteyourcam.usb.AppConfig;
21
+import com.remoteyourcam.usb.ptp.PacketUtil;
22
+import com.remoteyourcam.usb.ptp.PtpAction;
23
+import com.remoteyourcam.usb.ptp.PtpCamera;
24
+import com.remoteyourcam.usb.ptp.PtpConstants;
25
+import com.remoteyourcam.usb.ptp.PtpConstants.Type;
26
+
27
+import java.nio.ByteBuffer;
28
+
29
+/**
30
+ * Base class for all PTP commands.
31
+ */
32
+public abstract class Command implements PtpAction {
33
+
34
+    private static final String TAG = "Command";
35
+
36
+    protected final PtpCamera camera;
37
+
38
+    /**
39
+     * Deriving classes have to set this field to true if they want to send data
40
+     * from host to camera.
41
+     */
42
+    protected boolean hasDataToSend;
43
+
44
+    /**
45
+     * Received response code, should be handled in
46
+     * {@link #exec(com.remoteyourcam.usb.ptp.PtpCamera.IO)}.
47
+     */
48
+    protected int responseCode;
49
+
50
+    private boolean hasResponseReceived;
51
+
52
+    public Command(PtpCamera camera) {
53
+        this.camera = camera;
54
+    }
55
+
56
+    @Override
57
+    public abstract void exec(PtpCamera.IO io);
58
+
59
+    public abstract void encodeCommand(ByteBuffer b);
60
+
61
+    /**
62
+     * Derived classes should implement this method if they want to send data
63
+     * from host to camera. The field {@code hasDataToSend} has to be set to
64
+     * true for the sending to be done. The data to send must not be greater
65
+     * than the USB max packet size, any size below 256 should be save.
66
+     */
67
+    public void encodeData(ByteBuffer b) {
68
+    }
69
+
70
+    /**
71
+     * Derived classes should implement this method if they want to decode data
72
+     * received in an data packet that has been sent by the camera. The
73
+     * {@code ByteBuffer} already points to the first byte behind the
74
+     * transaction id, i.e. the payload.
75
+     */
76
+    protected void decodeData(ByteBuffer b, int length) {
77
+        if (AppConfig.LOG) {
78
+            Log.w(TAG, "Received data packet but handler not implemented");
79
+        }
80
+    }
81
+
82
+    /**
83
+     * Override if any special response data has to be decoded. The
84
+     * {@code ByteBuffer} already points to the first byte behind the
85
+     * transaction id, i.e. the payload.
86
+     */
87
+    protected void decodeResponse(ByteBuffer b, int length) {
88
+    }
89
+
90
+    public boolean hasDataToSend() {
91
+        return hasDataToSend;
92
+    }
93
+
94
+    public boolean hasResponseReceived() {
95
+        return hasResponseReceived;
96
+    }
97
+
98
+    public int getResponseCode() {
99
+        return responseCode;
100
+    }
101
+
102
+    public void receivedRead(ByteBuffer b) {
103
+        int length = b.getInt();
104
+        int type = b.getShort() & 0xFFFF;
105
+        int code = b.getShort() & 0xFFFF;
106
+        int tx = b.getInt();
107
+
108
+        if (AppConfig.LOG) {
109
+            Log.i(TAG,
110
+                    String.format("Received %s packet for %s, length %d, code %s, tx %d",
111
+                            PtpConstants.typeToString(type), getClass().getSimpleName(), length,
112
+                            PtpConstants.codeToString(type, code), tx));
113
+        }
114
+        if (AppConfig.LOG_PACKETS) {
115
+            PacketUtil.logHexdump(TAG, b.array(), length < 512 ? length : 512);
116
+        }
117
+
118
+        if (type == Type.Data) {
119
+            decodeData(b, length);
120
+        } else if (type == Type.Response) {
121
+            hasResponseReceived = true;
122
+            responseCode = code;
123
+            decodeResponse(b, length);
124
+        } else {
125
+            // error
126
+            hasResponseReceived = true;
127
+        }
128
+    }
129
+
130
+    /**
131
+     * Reset fields so this command may be requeued.
132
+     */
133
+    @Override
134
+    public void reset() {
135
+        responseCode = 0;
136
+        hasResponseReceived = false;
137
+    }
138
+
139
+    protected void encodeCommand(ByteBuffer b, int code) {
140
+        b.putInt(12);
141
+        b.putShort((short) Type.Command);
142
+        b.putShort((short) code);
143
+        b.putInt(camera.nextTransactionId());
144
+        if (AppConfig.LOG_PACKETS) {
145
+            Log.i(TAG, "command packet for " + getClass().getSimpleName());
146
+            PacketUtil.logHexdump(TAG, b.array(), 12);
147
+        }
148
+    }
149
+
150
+    protected void encodeCommand(ByteBuffer b, int code, int p0) {
151
+        b.putInt(16);
152
+        b.putShort((short) Type.Command);
153
+        b.putShort((short) code);
154
+        b.putInt(camera.nextTransactionId());
155
+        b.putInt(p0);
156
+        if (AppConfig.LOG_PACKETS) {
157
+            Log.i(TAG, "command packet for " + getClass().getSimpleName());
158
+            PacketUtil.logHexdump(TAG, b.array(), 16);
159
+        }
160
+    }
161
+
162
+    protected void encodeCommand(ByteBuffer b, int code, int p0, int p1) {
163
+        b.putInt(20);
164
+        b.putShort((short) Type.Command);
165
+        b.putShort((short) code);
166
+        b.putInt(camera.nextTransactionId());
167
+        b.putInt(p0);
168
+        b.putInt(p1);
169
+        if (AppConfig.LOG_PACKETS) {
170
+            Log.i(TAG, "command packet for " + getClass().getSimpleName());
171
+            PacketUtil.logHexdump(TAG, b.array(), 20);
172
+        }
173
+    }
174
+
175
+    protected void encodeCommand(ByteBuffer b, int code, int p0, int p1, int p2) {
176
+        b.putInt(24);
177
+        b.putShort((short) Type.Command);
178
+        b.putShort((short) code);
179
+        b.putInt(camera.nextTransactionId());
180
+        b.putInt(p0);
181
+        b.putInt(p1);
182
+        b.putInt(p2);
183
+        if (AppConfig.LOG_PACKETS) {
184
+            Log.i(TAG, "command packet for " + getClass().getSimpleName());
185
+            PacketUtil.logHexdump(TAG, b.array(), 24);
186
+        }
187
+    }
188
+}

+ 62 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetDeviceInfoCommand.java

@@ -0,0 +1,62 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpConstants;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+import com.remoteyourcam.usb.ptp.model.DeviceInfo;
26
+
27
+public class GetDeviceInfoCommand extends Command {
28
+
29
+    private DeviceInfo info;
30
+
31
+    public GetDeviceInfoCommand(PtpCamera camera) {
32
+        super(camera);
33
+    }
34
+
35
+    @Override
36
+    public void exec(IO io) {
37
+        io.handleCommand(this);
38
+        if (responseCode != Response.Ok) {
39
+            camera.onPtpError(String.format("Couldn't read device information, error code \"%s\"",
40
+                    PtpConstants.responseToString(responseCode)));
41
+        } else if (info == null) {
42
+            camera.onPtpError("Couldn't retrieve device information");
43
+        }
44
+    }
45
+
46
+    @Override
47
+    public void reset() {
48
+        super.reset();
49
+        info = null;
50
+    }
51
+
52
+    @Override
53
+    public void encodeCommand(ByteBuffer b) {
54
+        encodeCommand(b, Operation.GetDeviceInfo);
55
+    }
56
+
57
+    @Override
58
+    protected void decodeData(ByteBuffer b, int length) {
59
+        info = new DeviceInfo(b, length);
60
+        camera.setDeviceInfo(info);
61
+    }
62
+}

+ 57 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetDevicePropDescCommand.java

@@ -0,0 +1,57 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+import com.remoteyourcam.usb.ptp.model.DevicePropDesc;
24
+
25
+public class GetDevicePropDescCommand extends Command {
26
+
27
+    private final int property;
28
+    private DevicePropDesc devicePropDesc;
29
+
30
+    public GetDevicePropDescCommand(PtpCamera camera, int property) {
31
+        super(camera);
32
+        this.property = property;
33
+    }
34
+
35
+    @Override
36
+    public void exec(IO io) {
37
+        io.handleCommand(this);
38
+        if (responseCode == PtpConstants.Response.DeviceBusy) {
39
+            camera.onDeviceBusy(this, true);
40
+        }
41
+        if (devicePropDesc != null) {
42
+            // this order is important
43
+            camera.onPropertyDescChanged(property, devicePropDesc);
44
+            camera.onPropertyChanged(property, devicePropDesc.currentValue);
45
+        }
46
+    }
47
+
48
+    @Override
49
+    public void encodeCommand(ByteBuffer b) {
50
+        encodeCommand(b, PtpConstants.Operation.GetDevicePropDesc, property);
51
+    }
52
+
53
+    @Override
54
+    protected void decodeData(ByteBuffer b, int length) {
55
+        devicePropDesc = new DevicePropDesc(b, length);
56
+    }
57
+}

+ 68 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetDevicePropValueCommand.java

@@ -0,0 +1,68 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Datatype;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+
26
+public class GetDevicePropValueCommand extends Command {
27
+
28
+    private final int property;
29
+    private final int datatype;
30
+    private int value;
31
+
32
+    public GetDevicePropValueCommand(PtpCamera camera, int property, int datatype) {
33
+        super(camera);
34
+        this.property = property;
35
+        this.datatype = datatype;
36
+    }
37
+
38
+    @Override
39
+    public void exec(IO io) {
40
+        io.handleCommand(this);
41
+        if (responseCode == Response.DeviceBusy) {
42
+            camera.onDeviceBusy(this, true);
43
+        }
44
+        if (responseCode == Response.Ok) {
45
+            camera.onPropertyChanged(property, value);
46
+        }
47
+    }
48
+
49
+    @Override
50
+    public void encodeCommand(ByteBuffer b) {
51
+        encodeCommand(b, PtpConstants.Operation.GetDevicePropValue, property);
52
+    }
53
+
54
+    @Override
55
+    protected void decodeData(ByteBuffer b, int length) {
56
+        if (datatype == Datatype.int8) {
57
+            value = b.get();
58
+        } else if (datatype == Datatype.uint8) {
59
+            value = b.get() & 0xFF;
60
+        } else if (datatype == Datatype.uint16) {
61
+            value = b.getShort() & 0xFFFF;
62
+        } else if (datatype == Datatype.int16) {
63
+            value = b.getShort();
64
+        } else if (datatype == Datatype.int32 || datatype == Datatype.uint32) {
65
+            value = b.getInt();
66
+        }
67
+    }
68
+}

+ 90 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetObjectCommand.java

@@ -0,0 +1,90 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import android.graphics.Bitmap;
21
+import android.graphics.BitmapFactory;
22
+import android.util.Log;
23
+
24
+import com.remoteyourcam.usb.ptp.PtpCamera;
25
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
26
+import com.remoteyourcam.usb.ptp.PtpConstants;
27
+
28
+/**
29
+ * Read file data from camera with specified {@code objectHandle}.
30
+ */
31
+public class GetObjectCommand extends Command {
32
+
33
+    private static final String TAG = GetObjectCommand.class.getSimpleName();
34
+
35
+    private final int objectHandle;
36
+
37
+    private final BitmapFactory.Options options;
38
+    private Bitmap inBitmap;
39
+
40
+    private boolean outOfMemoryError;
41
+
42
+    public GetObjectCommand(PtpCamera camera, int objectHandle, int sampleSize) {
43
+        super(camera);
44
+        this.objectHandle = objectHandle;
45
+        options = new BitmapFactory.Options();
46
+        if (sampleSize >= 1 && sampleSize <= 4) {
47
+            options.inSampleSize = sampleSize;
48
+        } else {
49
+            options.inSampleSize = 2;
50
+        }
51
+    }
52
+
53
+    public Bitmap getBitmap() {
54
+        return inBitmap;
55
+    }
56
+
57
+    public boolean isOutOfMemoryError() {
58
+        return outOfMemoryError;
59
+    }
60
+
61
+    @Override
62
+    public void exec(IO io) {
63
+        throw new UnsupportedOperationException();
64
+    }
65
+
66
+    @Override
67
+    public void reset() {
68
+        super.reset();
69
+        inBitmap = null;
70
+        outOfMemoryError = false;
71
+    }
72
+
73
+    @Override
74
+    public void encodeCommand(ByteBuffer b) {
75
+        encodeCommand(b, PtpConstants.Operation.GetObject, objectHandle);
76
+    }
77
+
78
+    @Override
79
+    protected void decodeData(ByteBuffer b, int length) {
80
+        try {
81
+            // 12 == offset of data header
82
+            inBitmap = BitmapFactory.decodeByteArray(b.array(), 12, length - 12, options);
83
+        } catch (RuntimeException e) {
84
+            Log.i(TAG, "exception on decoding picture : " + e.toString());
85
+        } catch (OutOfMemoryError e) {
86
+            System.gc();
87
+            outOfMemoryError = true;
88
+        }
89
+    }
90
+}

+ 79 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetObjectHandlesCommand.java

@@ -0,0 +1,79 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.Camera.StorageInfoListener;
21
+import com.remoteyourcam.usb.ptp.PacketUtil;
22
+import com.remoteyourcam.usb.ptp.PtpCamera;
23
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
24
+import com.remoteyourcam.usb.ptp.PtpConstants;
25
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
26
+
27
+public class GetObjectHandlesCommand extends Command {
28
+
29
+    private final int storageId;
30
+    private final int objectFormat;
31
+    private final int associationHandle;
32
+    private int[] objectHandles;
33
+    private final StorageInfoListener listener;
34
+
35
+    public int[] getObjectHandles() {
36
+        if (objectHandles == null) {
37
+            return new int[0];
38
+        }
39
+        return objectHandles;
40
+    }
41
+
42
+    public GetObjectHandlesCommand(PtpCamera camera, StorageInfoListener listener, int storageId) {
43
+        this(camera, listener, storageId, 0, 0);
44
+    }
45
+
46
+    public GetObjectHandlesCommand(PtpCamera camera, StorageInfoListener listener, int storageId, int objectFormat) {
47
+        this(camera, listener, storageId, objectFormat, 0);
48
+    }
49
+
50
+    public GetObjectHandlesCommand(PtpCamera camera, StorageInfoListener listener, int storageId, int objectFormat,
51
+            int associationHandle) {
52
+        super(camera);
53
+        this.listener = listener;
54
+        this.storageId = storageId;
55
+        this.objectFormat = objectFormat;
56
+        this.associationHandle = associationHandle;
57
+    }
58
+
59
+    @Override
60
+    public void exec(IO io) {
61
+        io.handleCommand(this);
62
+        if (getResponseCode() != Response.Ok) {
63
+            // error
64
+            listener.onImageHandlesRetrieved(new int[0]);
65
+            return;
66
+        }
67
+        listener.onImageHandlesRetrieved(objectHandles);
68
+    }
69
+
70
+    @Override
71
+    public void encodeCommand(ByteBuffer b) {
72
+        super.encodeCommand(b, PtpConstants.Operation.GetObjectHandles, storageId, objectFormat, associationHandle);
73
+    }
74
+
75
+    @Override
76
+    protected void decodeData(ByteBuffer b, int length) {
77
+        objectHandles = PacketUtil.readU32Array(b);
78
+    }
79
+}

+ 73 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetObjectInfoCommand.java

@@ -0,0 +1,73 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.AppConfig;
21
+import com.remoteyourcam.usb.ptp.PtpCamera;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+import com.remoteyourcam.usb.ptp.model.ObjectInfo;
26
+
27
+import android.util.Log;
28
+
29
+public class GetObjectInfoCommand extends Command {
30
+
31
+    private final String TAG = GetObjectInfoCommand.class.getSimpleName();
32
+
33
+    private final int outObjectHandle;
34
+    private ObjectInfo inObjectInfo;
35
+
36
+    public GetObjectInfoCommand(PtpCamera camera, int objectHandle) {
37
+        super(camera);
38
+        this.outObjectHandle = objectHandle;
39
+    }
40
+
41
+    public ObjectInfo getObjectInfo() {
42
+        return inObjectInfo;
43
+    }
44
+
45
+    @Override
46
+    public void exec(IO io) {
47
+        io.handleCommand(this);
48
+        if (responseCode == Response.DeviceBusy) {
49
+            camera.onDeviceBusy(this, true);
50
+        }
51
+        if (inObjectInfo != null) {
52
+            if (AppConfig.LOG) {
53
+                Log.i(TAG, inObjectInfo.toString());
54
+            }
55
+        }
56
+    }
57
+
58
+    @Override
59
+    public void reset() {
60
+        super.reset();
61
+        inObjectInfo = null;
62
+    }
63
+
64
+    @Override
65
+    public void encodeCommand(ByteBuffer b) {
66
+        encodeCommand(b, PtpConstants.Operation.GetObjectInfo, outObjectHandle);
67
+    }
68
+
69
+    @Override
70
+    protected void decodeData(ByteBuffer b, int length) {
71
+        inObjectInfo = new ObjectInfo(b, length);
72
+    }
73
+}

+ 54 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetStorageIdsCommand.java

@@ -0,0 +1,54 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PacketUtil;
21
+import com.remoteyourcam.usb.ptp.PtpCamera;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants;
24
+
25
+public class GetStorageIdsCommand extends Command {
26
+
27
+    private int[] storageIds;
28
+
29
+    public int[] getStorageIds() {
30
+        if (storageIds == null) {
31
+            return new int[0];
32
+        }
33
+        return storageIds;
34
+    }
35
+
36
+    public GetStorageIdsCommand(PtpCamera camera) {
37
+        super(camera);
38
+    }
39
+
40
+    @Override
41
+    public void exec(IO io) {
42
+        io.handleCommand(this);
43
+    }
44
+
45
+    @Override
46
+    public void encodeCommand(ByteBuffer b) {
47
+        super.encodeCommand(b, PtpConstants.Operation.GetStorageIDs);
48
+    }
49
+
50
+    @Override
51
+    protected void decodeData(ByteBuffer b, int length) {
52
+        storageIds = PacketUtil.readU32Array(b);
53
+    }
54
+}

+ 53 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetStorageInfoCommand.java

@@ -0,0 +1,53 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+import com.remoteyourcam.usb.ptp.model.StorageInfo;
24
+
25
+public class GetStorageInfoCommand extends Command {
26
+
27
+    private StorageInfo storageInfo;
28
+    private final int storageId;
29
+
30
+    public StorageInfo getStorageInfo() {
31
+        return storageInfo;
32
+    }
33
+
34
+    public GetStorageInfoCommand(PtpCamera camera, int storageId) {
35
+        super(camera);
36
+        this.storageId = storageId;
37
+    }
38
+
39
+    @Override
40
+    public void exec(IO io) {
41
+        io.handleCommand(this);
42
+    }
43
+
44
+    @Override
45
+    public void encodeCommand(ByteBuffer b) {
46
+        super.encodeCommand(b, PtpConstants.Operation.GetStorageInfo, storageId);
47
+    }
48
+
49
+    @Override
50
+    protected void decodeData(ByteBuffer b, int length) {
51
+        storageInfo = new StorageInfo(b, length);
52
+    }
53
+}

+ 70 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetStorageInfosAction.java

@@ -0,0 +1,70 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import com.remoteyourcam.usb.ptp.Camera;
19
+import com.remoteyourcam.usb.ptp.Camera.StorageInfoListener;
20
+import com.remoteyourcam.usb.ptp.PtpAction;
21
+import com.remoteyourcam.usb.ptp.PtpCamera;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+
25
+public class GetStorageInfosAction implements PtpAction {
26
+
27
+    private final PtpCamera camera;
28
+    private final StorageInfoListener listener;
29
+
30
+    public GetStorageInfosAction(PtpCamera camera, Camera.StorageInfoListener listener) {
31
+        this.camera = camera;
32
+        this.listener = listener;
33
+    }
34
+
35
+    @Override
36
+    public void exec(IO io) {
37
+        GetStorageIdsCommand getStorageIds = new GetStorageIdsCommand(camera);
38
+        io.handleCommand(getStorageIds);
39
+
40
+        if (getStorageIds.getResponseCode() != Response.Ok) {
41
+            listener.onAllStoragesFound();
42
+            return;
43
+        }
44
+
45
+        int ids[] = getStorageIds.getStorageIds();
46
+        for (int i = 0; i < ids.length; ++i) {
47
+            int storageId = ids[i];
48
+            GetStorageInfoCommand c = new GetStorageInfoCommand(camera, storageId);
49
+            io.handleCommand(c);
50
+
51
+            if (c.getResponseCode() != Response.Ok) {
52
+                listener.onAllStoragesFound();
53
+                return;
54
+            }
55
+
56
+            String label = c.getStorageInfo().volumeLabel.isEmpty() ? c.getStorageInfo().storageDescription : c
57
+                    .getStorageInfo().volumeLabel;
58
+            if (label == null || label.isEmpty()) {
59
+                label = "Storage " + i;
60
+            }
61
+            listener.onStorageFound(storageId, label);
62
+        }
63
+
64
+        listener.onAllStoragesFound();
65
+    }
66
+
67
+    @Override
68
+    public void reset() {
69
+    }
70
+}

+ 71 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/GetThumb.java

@@ -0,0 +1,71 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import android.graphics.Bitmap;
21
+import android.graphics.BitmapFactory;
22
+import android.util.Log;
23
+
24
+import com.remoteyourcam.usb.ptp.PtpCamera;
25
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
26
+import com.remoteyourcam.usb.ptp.PtpConstants;
27
+
28
+public class GetThumb extends Command {
29
+
30
+    private static final String TAG = GetThumb.class.getSimpleName();
31
+
32
+    private final int objectHandle;
33
+    private Bitmap inBitmap;
34
+
35
+    public GetThumb(PtpCamera camera, int objectHandle) {
36
+        super(camera);
37
+        this.objectHandle = objectHandle;
38
+    }
39
+
40
+    public Bitmap getBitmap() {
41
+        return inBitmap;
42
+    }
43
+
44
+    @Override
45
+    public void exec(IO io) {
46
+        throw new UnsupportedOperationException();
47
+    }
48
+
49
+    @Override
50
+    public void reset() {
51
+        super.reset();
52
+        inBitmap = null;
53
+    }
54
+
55
+    @Override
56
+    public void encodeCommand(ByteBuffer b) {
57
+        encodeCommand(b, PtpConstants.Operation.GetThumb, objectHandle);
58
+    }
59
+
60
+    @Override
61
+    protected void decodeData(ByteBuffer b, int length) {
62
+        try {
63
+            // 12 == offset of data header
64
+            inBitmap = BitmapFactory.decodeByteArray(b.array(), 12, length - 12);
65
+        } catch (RuntimeException e) {
66
+            Log.i(TAG, "exception on decoding picture : " + e.toString());
67
+        } catch (OutOfMemoryError e) {
68
+            System.gc();
69
+        }
70
+    }
71
+}

+ 44 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/InitiateCaptureCommand.java

@@ -0,0 +1,44 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+
25
+public class InitiateCaptureCommand extends Command {
26
+
27
+    public InitiateCaptureCommand(PtpCamera camera) {
28
+        super(camera);
29
+    }
30
+
31
+    @Override
32
+    public void exec(IO io) {
33
+        io.handleCommand(this);
34
+        if (responseCode == Response.DeviceBusy) {
35
+            camera.onDeviceBusy(this, true); // TODO when nikon live view is enabled this stalls
36
+            return;
37
+        }
38
+    }
39
+
40
+    @Override
41
+    public void encodeCommand(ByteBuffer b) {
42
+        encodeCommand(b, Operation.InitiateCapture, 0, 0);
43
+    }
44
+}

+ 48 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/OpenSessionCommand.java

@@ -0,0 +1,48 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpConstants;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+
26
+public class OpenSessionCommand extends Command {
27
+
28
+    public OpenSessionCommand(PtpCamera camera) {
29
+        super(camera);
30
+    }
31
+
32
+    @Override
33
+    public void exec(IO io) {
34
+        io.handleCommand(this);
35
+        if (responseCode == Response.Ok) {
36
+            camera.onSessionOpened();
37
+        } else {
38
+            camera.onPtpError(String.format("Couldn't open session, error code \"%s\"",
39
+                    PtpConstants.responseToString(responseCode)));
40
+        }
41
+    }
42
+
43
+    @Override
44
+    public void encodeCommand(ByteBuffer b) {
45
+        camera.resetTransactionId();
46
+        encodeCommand(b, Operation.OpenSession, 1);
47
+    }
48
+}

+ 51 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/RetrieveAddedObjectInfoAction.java

@@ -0,0 +1,51 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import com.remoteyourcam.usb.ptp.PtpAction;
19
+import com.remoteyourcam.usb.ptp.PtpCamera;
20
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
21
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
22
+
23
+public class RetrieveAddedObjectInfoAction implements PtpAction {
24
+
25
+    private final PtpCamera camera;
26
+    private final int objectHandle;
27
+
28
+    public RetrieveAddedObjectInfoAction(PtpCamera camera, int objectHandle) {
29
+        this.camera = camera;
30
+        this.objectHandle = objectHandle;
31
+    }
32
+
33
+    @Override
34
+    public void exec(IO io) {
35
+        GetObjectInfoCommand getInfo = new GetObjectInfoCommand(camera, objectHandle);
36
+        io.handleCommand(getInfo);
37
+
38
+        if (getInfo.getResponseCode() != Response.Ok) {
39
+            return;
40
+        }
41
+        if (getInfo.getObjectInfo() == null) {
42
+            return;
43
+        }
44
+
45
+        camera.onEventObjectAdded(objectHandle, getInfo.getObjectInfo().objectFormat);
46
+    }
47
+
48
+    @Override
49
+    public void reset() {
50
+    }
51
+}

+ 54 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/RetrieveImageAction.java

@@ -0,0 +1,54 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import com.remoteyourcam.usb.ptp.Camera.RetrieveImageListener;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
23
+
24
+public class RetrieveImageAction implements PtpAction {
25
+
26
+    private final PtpCamera camera;
27
+    private final int objectHandle;
28
+    private final RetrieveImageListener listener;
29
+    private final int sampleSize;
30
+
31
+    public RetrieveImageAction(PtpCamera camera, RetrieveImageListener listener, int objectHandle, int sampleSize) {
32
+        this.camera = camera;
33
+        this.listener = listener;
34
+        this.objectHandle = objectHandle;
35
+        this.sampleSize = sampleSize;
36
+    }
37
+
38
+    @Override
39
+    public void exec(IO io) {
40
+        GetObjectCommand getObject = new GetObjectCommand(camera, objectHandle, sampleSize);
41
+        io.handleCommand(getObject);
42
+
43
+        if (getObject.getResponseCode() != Response.Ok || getObject.getBitmap() == null) {
44
+            listener.onImageRetrieved(0, null);
45
+            return;
46
+        }
47
+
48
+        listener.onImageRetrieved(objectHandle, getObject.getBitmap());
49
+    }
50
+
51
+    @Override
52
+    public void reset() {
53
+    }
54
+}

+ 70 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/RetrieveImageInfoAction.java

@@ -0,0 +1,70 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import android.graphics.Bitmap;
19
+
20
+import com.remoteyourcam.usb.ptp.Camera.RetrieveImageInfoListener;
21
+import com.remoteyourcam.usb.ptp.PtpAction;
22
+import com.remoteyourcam.usb.ptp.PtpCamera;
23
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
24
+import com.remoteyourcam.usb.ptp.PtpConstants;
25
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
26
+import com.remoteyourcam.usb.ptp.model.ObjectInfo;
27
+
28
+public class RetrieveImageInfoAction implements PtpAction {
29
+
30
+    private final PtpCamera camera;
31
+    private final int objectHandle;
32
+    private final RetrieveImageInfoListener listener;
33
+
34
+    public RetrieveImageInfoAction(PtpCamera camera, RetrieveImageInfoListener listener, int objectHandle) {
35
+        this.camera = camera;
36
+        this.listener = listener;
37
+        this.objectHandle = objectHandle;
38
+    }
39
+
40
+    @Override
41
+    public void exec(IO io) {
42
+        GetObjectInfoCommand getInfo = new GetObjectInfoCommand(camera, objectHandle);
43
+        io.handleCommand(getInfo);
44
+
45
+        if (getInfo.getResponseCode() != Response.Ok) {
46
+            return;
47
+        }
48
+
49
+        ObjectInfo objectInfo = getInfo.getObjectInfo();
50
+        if (objectInfo == null) {
51
+            return;
52
+        }
53
+
54
+        Bitmap thumbnail = null;
55
+        if (objectInfo.thumbFormat == PtpConstants.ObjectFormat.JFIF
56
+                || objectInfo.thumbFormat == PtpConstants.ObjectFormat.EXIF_JPEG) {
57
+            GetThumb getThumb = new GetThumb(camera, objectHandle);
58
+            io.handleCommand(getThumb);
59
+            if (getThumb.getResponseCode() == Response.Ok) {
60
+                thumbnail = getThumb.getBitmap();
61
+            }
62
+        }
63
+
64
+        listener.onImageInfoRetrieved(objectHandle, getInfo.getObjectInfo(), thumbnail);
65
+    }
66
+
67
+    @Override
68
+    public void reset() {
69
+    }
70
+}

+ 86 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/RetrievePictureAction.java

@@ -0,0 +1,86 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import android.graphics.Bitmap;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpAction;
21
+import com.remoteyourcam.usb.ptp.PtpCamera;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+import com.remoteyourcam.usb.ptp.model.ObjectInfo;
26
+
27
+public class RetrievePictureAction implements PtpAction {
28
+
29
+    private final PtpCamera camera;
30
+    private final int objectHandle;
31
+    private final int sampleSize;
32
+
33
+    public RetrievePictureAction(PtpCamera camera, int objectHandle, int sampleSize) {
34
+        this.camera = camera;
35
+        this.objectHandle = objectHandle;
36
+        this.sampleSize = sampleSize;
37
+    }
38
+
39
+    @Override
40
+    public void exec(IO io) {
41
+        GetObjectInfoCommand getInfo = new GetObjectInfoCommand(camera, objectHandle);
42
+        io.handleCommand(getInfo);
43
+
44
+        if (getInfo.getResponseCode() != Response.Ok) {
45
+            return;
46
+        }
47
+
48
+        ObjectInfo objectInfo = getInfo.getObjectInfo();
49
+        if (objectInfo == null) {
50
+            return;
51
+        }
52
+
53
+        Bitmap thumbnail = null;
54
+        if (objectInfo.thumbFormat == PtpConstants.ObjectFormat.JFIF
55
+                || objectInfo.thumbFormat == PtpConstants.ObjectFormat.EXIF_JPEG) {
56
+            GetThumb getThumb = new GetThumb(camera, objectHandle);
57
+            io.handleCommand(getThumb);
58
+            if (getThumb.getResponseCode() == Response.Ok) {
59
+                thumbnail = getThumb.getBitmap();
60
+            }
61
+        }
62
+
63
+        GetObjectCommand getObject = new GetObjectCommand(camera, objectHandle, sampleSize);
64
+        io.handleCommand(getObject);
65
+
66
+        if (getObject.getResponseCode() != Response.Ok) {
67
+            return;
68
+        }
69
+        if (getObject.getBitmap() == null) {
70
+            if (getObject.isOutOfMemoryError()) {
71
+                camera.onPictureReceived(objectHandle, getInfo.getObjectInfo().filename, thumbnail, null);
72
+            }
73
+            return;
74
+        }
75
+
76
+        if (thumbnail == null) {
77
+            // TODO resize real picture?
78
+        }
79
+
80
+        camera.onPictureReceived(objectHandle, getInfo.getObjectInfo().filename, thumbnail, getObject.getBitmap());
81
+    }
82
+
83
+    @Override
84
+    public void reset() {
85
+    }
86
+}

+ 76 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/SetDevicePropValueCommand.java

@@ -0,0 +1,76 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Datatype;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
25
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
26
+import com.remoteyourcam.usb.ptp.PtpConstants.Type;
27
+
28
+public class SetDevicePropValueCommand extends Command {
29
+
30
+    private final int property;
31
+    private final int value;
32
+    private final int datatype;
33
+
34
+    public SetDevicePropValueCommand(PtpCamera camera, int property, int value, int datatype) {
35
+        super(camera);
36
+        this.property = property;
37
+        this.value = value;
38
+        this.datatype = datatype;
39
+        hasDataToSend = true;
40
+    }
41
+
42
+    @Override
43
+    public void exec(IO io) {
44
+        io.handleCommand(this);
45
+        if (responseCode == Response.DeviceBusy) {
46
+            camera.onDeviceBusy(this, true);
47
+            return;
48
+        } else if (responseCode == Response.Ok) {
49
+            camera.onPropertyChanged(property, value);
50
+        }
51
+    }
52
+
53
+    @Override
54
+    public void encodeCommand(ByteBuffer b) {
55
+        encodeCommand(b, Operation.SetDevicePropValue, property);
56
+    }
57
+
58
+    @Override
59
+    public void encodeData(ByteBuffer b) {
60
+        // header
61
+        b.putInt(12 + PtpConstants.getDatatypeSize(datatype));
62
+        b.putShort((short) Type.Data);
63
+        b.putShort((short) Operation.SetDevicePropValue);
64
+        b.putInt(camera.currentTransactionId());
65
+        // specific block
66
+        if (datatype == Datatype.int8 || datatype == Datatype.uint8) {
67
+            b.put((byte) value);
68
+        } else if (datatype == Datatype.int16 || datatype == Datatype.uint16) {
69
+            b.putShort((short) value);
70
+        } else if (datatype == Datatype.int32 || datatype == Datatype.uint32) {
71
+            b.putInt(value);
72
+        } else {
73
+            throw new UnsupportedOperationException();
74
+        }
75
+    }
76
+}

+ 70 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/SimpleCommand.java

@@ -0,0 +1,70 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PtpCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
23
+
24
+public class SimpleCommand extends Command {
25
+
26
+    private final int operation;
27
+    private int numParams;
28
+    private int p0;
29
+    private int p1;
30
+
31
+    public SimpleCommand(PtpCamera camera, int operation) {
32
+        super(camera);
33
+        this.operation = operation;
34
+    }
35
+
36
+    public SimpleCommand(PtpCamera camera, int operation, int p0) {
37
+        super(camera);
38
+        this.operation = operation;
39
+        this.p0 = p0;
40
+        this.numParams = 1;
41
+    }
42
+
43
+    public SimpleCommand(PtpCamera camera, int operation, int p0, int p1) {
44
+        super(camera);
45
+        this.operation = operation;
46
+        this.p0 = p0;
47
+        this.p1 = p1;
48
+        this.numParams = 2;
49
+    }
50
+
51
+    @Override
52
+    public void exec(IO io) {
53
+        io.handleCommand(this);
54
+        if (responseCode == Response.DeviceBusy) {
55
+            camera.onDeviceBusy(this, true);
56
+            return;
57
+        }
58
+    }
59
+
60
+    @Override
61
+    public void encodeCommand(ByteBuffer b) {
62
+        if (numParams == 2) {
63
+            encodeCommand(b, operation, p0, p1);
64
+        } else if (numParams == 1) {
65
+            encodeCommand(b, operation, p0);
66
+        } else {
67
+            encodeCommand(b, operation);
68
+        }
69
+    }
70
+}

+ 29 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosCommand.java

@@ -0,0 +1,29 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import com.remoteyourcam.usb.ptp.EosCamera;
19
+import com.remoteyourcam.usb.ptp.commands.Command;
20
+
21
+public abstract class EosCommand extends Command {
22
+
23
+    protected EosCamera camera;
24
+
25
+    public EosCommand(EosCamera camera) {
26
+        super(camera);
27
+        this.camera = camera;
28
+    }
29
+}

+ 184 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosEventCheckCommand.java

@@ -0,0 +1,184 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import android.util.Log;
21
+
22
+import com.remoteyourcam.usb.AppConfig;
23
+import com.remoteyourcam.usb.ptp.EosCamera;
24
+import com.remoteyourcam.usb.ptp.PacketUtil;
25
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
26
+import com.remoteyourcam.usb.ptp.PtpConstants;
27
+import com.remoteyourcam.usb.ptp.PtpConstants.Event;
28
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
29
+import com.remoteyourcam.usb.ptp.PtpConstants.Property;
30
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
31
+
32
+public class EosEventCheckCommand extends EosCommand {
33
+
34
+    private static final String TAG = EosEventCheckCommand.class.getSimpleName();
35
+
36
+    public EosEventCheckCommand(EosCamera camera) {
37
+        super(camera);
38
+    }
39
+
40
+    @Override
41
+    public void exec(IO io) {
42
+        io.handleCommand(this);
43
+        if (responseCode == Response.DeviceBusy) {
44
+            camera.onDeviceBusy(this, false);
45
+        }
46
+    }
47
+
48
+    @Override
49
+    public void encodeCommand(ByteBuffer b) {
50
+        encodeCommand(b, Operation.EosEventCheck);
51
+    }
52
+
53
+    @Override
54
+    protected void decodeData(ByteBuffer b, int length) {
55
+        while (b.position() < length) {
56
+            int eventLength = b.getInt();
57
+            int event = b.getInt();
58
+            if (AppConfig.LOG) {
59
+                Log.i(TAG, "event length " + eventLength);
60
+                Log.i(TAG, "event type " + PtpConstants.eventToString(event));
61
+            }
62
+            switch (event) {
63
+            case Event.EosObjectAdded: {
64
+                int objectHandle = b.getInt();
65
+                int storageId = b.getInt();
66
+                int objectFormat = b.getShort();
67
+                skip(b, eventLength - 18);
68
+                camera.onEventDirItemCreated(objectHandle, storageId, objectFormat, "TODO");
69
+                break;
70
+            }
71
+            case Event.EosDevicePropChanged: {
72
+                int property = b.getInt();
73
+                if (AppConfig.LOG) {
74
+                    Log.i(TAG, "property " + PtpConstants.propertyToString(property));
75
+                }
76
+                switch (property) {
77
+                case Property.EosApertureValue:
78
+                case Property.EosShutterSpeed:
79
+                case Property.EosIsoSpeed:
80
+                case Property.EosWhitebalance:
81
+                case Property.EosEvfOutputDevice:
82
+                case Property.EosShootingMode:
83
+                case Property.EosAvailableShots:
84
+                case Property.EosColorTemperature:
85
+                case Property.EosAfMode:
86
+                case Property.EosMeteringMode:
87
+                case Property.EosExposureCompensation:
88
+                case Property.EosPictureStyle:
89
+                case Property.EosEvfMode: {
90
+                    int value = b.getInt();
91
+                    if (AppConfig.LOG) {
92
+                        Log.i(TAG, "value " + value);
93
+                    }
94
+                    camera.onPropertyChanged(property, value);
95
+                    break;
96
+                }
97
+                default:
98
+                    if (AppConfig.LOG && eventLength <= 200) {
99
+                        PacketUtil.logHexdump(TAG, b.array(), b.position(), eventLength - 12);
100
+                    }
101
+                    skip(b, eventLength - 12);
102
+                    break;
103
+                }
104
+                break;
105
+            }
106
+            case Event.EosDevicePropDescChanged: {
107
+                int property = b.getInt();
108
+                if (AppConfig.LOG) {
109
+                    Log.i(TAG, "property " + PtpConstants.propertyToString(property));
110
+                }
111
+                switch (property) {
112
+                case Property.EosApertureValue:
113
+                case Property.EosShutterSpeed:
114
+                case Property.EosIsoSpeed:
115
+                case Property.EosMeteringMode:
116
+                case Property.EosPictureStyle:
117
+                case Property.EosExposureCompensation:
118
+                case Property.EosColorTemperature:
119
+                case Property.EosWhitebalance: {
120
+                    /* int dataType = */b.getInt();
121
+                    int num = b.getInt();
122
+                    if (AppConfig.LOG) {
123
+                        Log.i(TAG, "property desc with num " + num);
124
+                    }
125
+                    if (eventLength != 20 + 4 * num) {
126
+                        if (AppConfig.LOG) {
127
+                            Log.i(TAG, String.format("Event Desc length invalid should be %d but is %d", 20 + 4 * num,
128
+                                    eventLength));
129
+                            PacketUtil.logHexdump(TAG, b.array(), b.position() - 20, eventLength);
130
+                        }
131
+                    }
132
+                    int[] values = new int[num];
133
+                    for (int i = 0; i < num; ++i) {
134
+                        values[i] = b.getInt();
135
+                    }
136
+                    if (eventLength != 20 + 4 * num) {
137
+                        for (int i = 20 + 4 * num; i < eventLength; ++i) {
138
+                            b.get();
139
+                        }
140
+                    }
141
+                    camera.onPropertyDescChanged(property, values);
142
+                    break;
143
+                }
144
+                default:
145
+                    if (AppConfig.LOG && eventLength <= 50) {
146
+                        PacketUtil.logHexdump(TAG, b.array(), b.position(), eventLength - 12);
147
+                    }
148
+                    skip(b, eventLength - 12);
149
+                }
150
+                break;
151
+            }
152
+            case Event.EosBulbExposureTime: {
153
+                int seconds = b.getInt();
154
+                camera.onBulbExposureTime(seconds);
155
+                break;
156
+            }
157
+            case Event.EosCameraStatus: {
158
+                // 0 - capture stopped
159
+                // 1 - capture started
160
+                int status = b.getInt();
161
+                camera.onEventCameraCapture(status != 0);
162
+                break;
163
+            }
164
+            case Event.EosWillSoonShutdown: {
165
+                /* int seconds = */b.getInt();
166
+                //TODO
167
+                break;
168
+            }
169
+            default:
170
+                //                if (BuildConfig.LOG) {
171
+                //                    PacketUtil.logHexdump(b.array(), b.position(), eventLength - 8);
172
+                //                }
173
+                skip(b, eventLength - 8);
174
+                break;
175
+            }
176
+        }
177
+    }
178
+
179
+    private void skip(ByteBuffer b, int length) {
180
+        for (int i = 0; i < length; ++i) {
181
+            b.get();
182
+        }
183
+    }
184
+}

+ 153 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosGetLiveViewPictureCommand.java

@@ -0,0 +1,153 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import java.nio.ByteBuffer;
19
+import java.nio.ByteOrder;
20
+
21
+import android.graphics.BitmapFactory;
22
+import android.graphics.BitmapFactory.Options;
23
+import android.util.Log;
24
+
25
+import com.remoteyourcam.usb.AppConfig;
26
+import com.remoteyourcam.usb.ptp.EosCamera;
27
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
28
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
29
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
30
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
31
+
32
+public class EosGetLiveViewPictureCommand extends EosCommand {
33
+
34
+    private static final String TAG = EosGetLiveViewPictureCommand.class.getSimpleName();
35
+    private static byte[] tmpStorage = new byte[0x4000];
36
+    private final Options options;
37
+    private LiveViewData data;
38
+
39
+    public EosGetLiveViewPictureCommand(EosCamera camera, LiveViewData data) {
40
+        super(camera);
41
+        if (data == null) {
42
+            this.data = new LiveViewData();
43
+            this.data.histogram = ByteBuffer.allocate(1024 * 4);
44
+            this.data.histogram.order(ByteOrder.LITTLE_ENDIAN);
45
+        } else {
46
+            this.data = data;
47
+        }
48
+        options = new BitmapFactory.Options();
49
+        options.inBitmap = this.data.bitmap;
50
+        options.inSampleSize = 1;
51
+        options.inTempStorage = tmpStorage;
52
+        this.data.bitmap = null;
53
+    }
54
+
55
+    @Override
56
+    public void exec(IO io) {
57
+        io.handleCommand(this);
58
+        if (responseCode == Response.DeviceBusy) {
59
+            camera.onDeviceBusy(this, true);
60
+            return;
61
+        }
62
+        if (this.data.bitmap != null && responseCode == Response.Ok) {
63
+            camera.onLiveViewReceived(data);
64
+        } else {
65
+            camera.onLiveViewReceived(null);
66
+        }
67
+    }
68
+
69
+    @Override
70
+    public void encodeCommand(ByteBuffer b) {
71
+        encodeCommand(b, Operation.EosGetLiveViewPicture, 0x100000);
72
+    }
73
+
74
+    @Override
75
+    protected void decodeData(ByteBuffer b, int length) {
76
+
77
+        data.hasHistogram = false;
78
+        data.hasAfFrame = false;
79
+
80
+        if (length < 1000) {
81
+            if (AppConfig.LOG) {
82
+                Log.w(TAG, String.format("liveview data size too small %d", length));
83
+            }
84
+            return;
85
+        }
86
+
87
+        try {
88
+
89
+            while (b.hasRemaining()) {
90
+                int subLength = b.getInt();
91
+                int type = b.getInt();
92
+
93
+                if (subLength < 8) {
94
+                    throw new RuntimeException("Invalid sub size " + subLength);
95
+                }
96
+
97
+                int unknownInt = 0;
98
+
99
+                switch (type) {
100
+                case 0x01:
101
+                    data.bitmap = BitmapFactory.decodeByteArray(b.array(), b.position(), subLength - 8, options);
102
+                    b.position(b.position() + subLength - 8);
103
+                    break;
104
+                case 0x04:
105
+                    data.zoomFactor = b.getInt();
106
+                    break;
107
+                case 0x05:
108
+                    // zoomfocusx, zoomfocusy
109
+                    data.zoomRectRight = b.getInt();
110
+                    data.zoomRectBottom = b.getInt();
111
+                    if (AppConfig.LOG) {
112
+                        Log.i(TAG, "header 5 " + data.zoomRectRight + " " + data.zoomRectBottom);
113
+                    }
114
+                    break;
115
+                case 0x06:
116
+                    // imagex, imagey (if zoomed should be non zero)
117
+                    data.zoomRectLeft = b.getInt();
118
+                    data.zoomRectTop = b.getInt();
119
+                    if (AppConfig.LOG) {
120
+                        Log.i(TAG, "header 6 " + data.zoomRectLeft + " " + data.zoomRectTop);
121
+                    }
122
+                    break;
123
+                case 0x07:
124
+                    unknownInt = b.getInt();
125
+                    if (AppConfig.LOG) {
126
+                        Log.i(TAG, "header 7 " + unknownInt + " " + subLength);
127
+                    }
128
+                    break;
129
+                case 0x03:
130
+                    data.hasHistogram = true;
131
+                    b.get(data.histogram.array(), 0, 1024 * 4);
132
+                    break;
133
+                case 0x08: // faces if faces focus
134
+                case 0x0e: // TODO original width, original height
135
+                default:
136
+                    b.position(b.position() + subLength - 8);
137
+                    if (AppConfig.LOG) {
138
+                        Log.i(TAG, "unknown header " + type + " size " + subLength);
139
+                    }
140
+                    break;
141
+                }
142
+
143
+                if (length - b.position() < 8) {
144
+                    break;
145
+                }
146
+            }
147
+
148
+        } catch (RuntimeException e) {
149
+            Log.e(TAG, "" + e.toString());
150
+            Log.e(TAG, "" + e.getLocalizedMessage());
151
+        }
152
+    }
153
+}

+ 65 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosOpenSessionAction.java

@@ -0,0 +1,65 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import com.remoteyourcam.usb.ptp.EosCamera;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpConstants;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.commands.OpenSessionCommand;
23
+
24
+public class EosOpenSessionAction implements PtpAction {
25
+
26
+    private final EosCamera camera;
27
+
28
+    public EosOpenSessionAction(EosCamera camera) {
29
+        this.camera = camera;
30
+    }
31
+
32
+    @Override
33
+    public void exec(IO io) {
34
+        OpenSessionCommand openSession = new OpenSessionCommand(camera);
35
+        io.handleCommand(openSession);
36
+        if (openSession.getResponseCode() == PtpConstants.Response.Ok) {
37
+            EosSetPcModeCommand setPcMode = new EosSetPcModeCommand(camera);
38
+            io.handleCommand(setPcMode);
39
+            if (setPcMode.getResponseCode() == PtpConstants.Response.Ok) {
40
+                EosSetExtendedEventInfoCommand c = new EosSetExtendedEventInfoCommand(camera);
41
+                io.handleCommand(c);
42
+                if (c.getResponseCode() == PtpConstants.Response.Ok) {
43
+                    camera.onSessionOpened();
44
+                    return;
45
+                } else {
46
+                    camera.onPtpError(String.format(
47
+                            "Couldn't open session! Setting extended event info failed with error code \"%s\"",
48
+                            PtpConstants.responseToString(c.getResponseCode())));
49
+                }
50
+            } else {
51
+                camera.onPtpError(String.format(
52
+                        "Couldn't open session! Setting PcMode property failed with error code \"%s\"",
53
+                        PtpConstants.responseToString(setPcMode.getResponseCode())));
54
+            }
55
+        } else {
56
+            camera.onPtpError(String.format(
57
+                    "Couldn't open session! Open session command failed with error code \"%s\"",
58
+                    PtpConstants.responseToString(openSession.getResponseCode())));
59
+        }
60
+    }
61
+
62
+    @Override
63
+    public void reset() {
64
+    }
65
+}

+ 46 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosSetExtendedEventInfoCommand.java

@@ -0,0 +1,46 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.EosCamera;
21
+import com.remoteyourcam.usb.ptp.PtpConstants;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+
26
+public class EosSetExtendedEventInfoCommand extends EosCommand {
27
+
28
+    public EosSetExtendedEventInfoCommand(EosCamera camera) {
29
+        super(camera);
30
+    }
31
+
32
+    @Override
33
+    public void exec(IO io) {
34
+        io.handleCommand(this);
35
+        if (responseCode != Response.Ok) {
36
+            camera.onPtpError(String.format(
37
+                    "Couldn't initialize session! Setting extended event info failed, error code %s",
38
+                    PtpConstants.responseToString(responseCode)));
39
+        }
40
+    }
41
+
42
+    @Override
43
+    public void encodeCommand(ByteBuffer b) {
44
+        encodeCommand(b, Operation.EosSetEventMode, 1);
45
+    }
46
+}

+ 84 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosSetLiveViewAction.java

@@ -0,0 +1,84 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import com.remoteyourcam.usb.ptp.EosCamera;
19
+import com.remoteyourcam.usb.ptp.EosConstants;
20
+import com.remoteyourcam.usb.ptp.PtpAction;
21
+import com.remoteyourcam.usb.ptp.EosConstants.EvfMode;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Property;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+
26
+public class EosSetLiveViewAction implements PtpAction {
27
+
28
+    private final EosCamera camera;
29
+    private final boolean enabled;
30
+
31
+    public EosSetLiveViewAction(EosCamera camera, boolean enabled) {
32
+        this.camera = camera;
33
+        this.enabled = enabled;
34
+    }
35
+
36
+    @Override
37
+    public void exec(IO io) {
38
+        int evfMode = camera.getPtpProperty(Property.EosEvfMode);
39
+
40
+        if (enabled && evfMode != EvfMode.ENABLE || !enabled && evfMode != EvfMode.DISABLE) {
41
+            EosSetPropertyCommand setEvfMode = new EosSetPropertyCommand(camera, Property.EosEvfMode,
42
+                    enabled ? EvfMode.ENABLE : EvfMode.DISABLE);
43
+            io.handleCommand(setEvfMode);
44
+
45
+            if (setEvfMode.getResponseCode() == Response.DeviceBusy) {
46
+                camera.onDeviceBusy(this, true);
47
+                return;
48
+            } else if (setEvfMode.getResponseCode() != Response.Ok) {
49
+                camera.onPtpWarning("Couldn't open live view");
50
+                return;
51
+            }
52
+        }
53
+
54
+        int outputDevice = camera.getPtpProperty(Property.EosEvfOutputDevice);
55
+
56
+        if (enabled) {
57
+            outputDevice |= EosConstants.EvfOutputDevice.PC;
58
+        } else {
59
+            outputDevice &= ~EosConstants.EvfOutputDevice.PC;
60
+        }
61
+
62
+        EosSetPropertyCommand setOutputDevice = new EosSetPropertyCommand(camera, Property.EosEvfOutputDevice,
63
+                outputDevice);
64
+        io.handleCommand(setOutputDevice);
65
+
66
+        if (setOutputDevice.getResponseCode() == Response.DeviceBusy) {
67
+            camera.onDeviceBusy(this, true);
68
+        } else if (setOutputDevice.getResponseCode() == Response.Ok) {
69
+            if (!enabled) {
70
+                camera.onLiveViewStopped();
71
+            } else {
72
+                camera.onLiveViewStarted();
73
+            }
74
+            return;
75
+        } else {
76
+            camera.onPtpWarning("Couldn't open live view");
77
+        }
78
+
79
+    }
80
+
81
+    @Override
82
+    public void reset() {
83
+    }
84
+}

+ 45 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosSetPcModeCommand.java

@@ -0,0 +1,45 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.EosCamera;
21
+import com.remoteyourcam.usb.ptp.PtpConstants;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
25
+
26
+public class EosSetPcModeCommand extends EosCommand {
27
+
28
+    public EosSetPcModeCommand(EosCamera camera) {
29
+        super(camera);
30
+    }
31
+
32
+    @Override
33
+    public void exec(IO io) {
34
+        io.handleCommand(this);
35
+        if (responseCode != Response.Ok) {
36
+            camera.onPtpError(String.format("Couldn't initialize session! setting PC Mode failed, error code %s",
37
+                    PtpConstants.responseToString(responseCode)));
38
+        }
39
+    }
40
+
41
+    @Override
42
+    public void encodeCommand(ByteBuffer b) {
43
+        encodeCommand(b, Operation.EosSetPCConnectMode, 1);
44
+    }
45
+}

+ 64 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosSetPropertyCommand.java

@@ -0,0 +1,64 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.EosCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Type;
25
+
26
+public class EosSetPropertyCommand extends EosCommand {
27
+
28
+    private final int property;
29
+    private final int value;
30
+
31
+    public EosSetPropertyCommand(EosCamera camera, int property, int value) {
32
+        super(camera);
33
+        hasDataToSend = true;
34
+        this.property = property;
35
+        this.value = value;
36
+    }
37
+
38
+    @Override
39
+    public void exec(IO io) {
40
+        io.handleCommand(this);
41
+        if (responseCode == Response.DeviceBusy) {
42
+            camera.onDeviceBusy(this, true);
43
+            return;
44
+        }
45
+    }
46
+
47
+    @Override
48
+    public void encodeCommand(ByteBuffer b) {
49
+        encodeCommand(b, Operation.EosSetDevicePropValue);
50
+    }
51
+
52
+    @Override
53
+    public void encodeData(ByteBuffer b) {
54
+        // header
55
+        b.putInt(24);
56
+        b.putShort((short) Type.Data);
57
+        b.putShort((short) Operation.EosSetDevicePropValue);
58
+        b.putInt(camera.currentTransactionId());
59
+        // specific block
60
+        b.putInt(0x0C);
61
+        b.putInt(property);
62
+        b.putInt(value);
63
+    }
64
+}

+ 43 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/eos/EosTakePictureCommand.java

@@ -0,0 +1,43 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.eos;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.EosCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+
25
+public class EosTakePictureCommand extends EosCommand {
26
+
27
+    public EosTakePictureCommand(EosCamera camera) {
28
+        super(camera);
29
+    }
30
+
31
+    @Override
32
+    public void exec(IO io) {
33
+        io.handleCommand(this);
34
+        if (responseCode == Response.DeviceBusy) {
35
+            camera.onDeviceBusy(this, true);
36
+        }
37
+    }
38
+
39
+    @Override
40
+    public void encodeCommand(ByteBuffer b) {
41
+        encodeCommand(b, Operation.EosTakePicture);
42
+    }
43
+}

+ 47 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonAfDriveCommand.java

@@ -0,0 +1,47 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.NikonCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+
25
+public class NikonAfDriveCommand extends NikonCommand {
26
+
27
+    public NikonAfDriveCommand(NikonCamera camera) {
28
+        super(camera);
29
+    }
30
+
31
+    @Override
32
+    public void exec(IO io) {
33
+        //        if (camera.isInActivationTypePhase()) {
34
+        //            return;
35
+        //        }
36
+        io.handleCommand(this);
37
+        if (getResponseCode() == Response.Ok) {
38
+            camera.onFocusStarted();
39
+            camera.enqueue(new NikonAfDriveDeviceReadyCommand(camera), 200);
40
+        }
41
+    }
42
+
43
+    @Override
44
+    public void encodeCommand(ByteBuffer b) {
45
+        encodeCommand(b, Operation.NikonAfDrive);
46
+    }
47
+}

+ 46 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonAfDriveDeviceReadyCommand.java

@@ -0,0 +1,46 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.NikonCamera;
21
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+
25
+public class NikonAfDriveDeviceReadyCommand extends NikonCommand {
26
+
27
+    public NikonAfDriveDeviceReadyCommand(NikonCamera camera) {
28
+        super(camera);
29
+    }
30
+
31
+    @Override
32
+    public void exec(IO io) {
33
+        io.handleCommand(this);
34
+        if (getResponseCode() == Response.DeviceBusy) {
35
+            reset();
36
+            camera.enqueue(this, 200);
37
+        } else {
38
+            camera.onFocusEnded(getResponseCode() == Response.Ok);
39
+        }
40
+    }
41
+
42
+    @Override
43
+    public void encodeCommand(ByteBuffer b) {
44
+        encodeCommand(b, Operation.NikonDeviceReady);
45
+    }
46
+}

+ 54 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonCloseSessionAction.java

@@ -0,0 +1,54 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import com.remoteyourcam.usb.ptp.NikonCamera;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
21
+import com.remoteyourcam.usb.ptp.PtpConstants.Datatype;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Property;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
24
+import com.remoteyourcam.usb.ptp.commands.CloseSessionCommand;
25
+import com.remoteyourcam.usb.ptp.commands.SetDevicePropValueCommand;
26
+
27
+public class NikonCloseSessionAction implements PtpAction {
28
+
29
+    private final NikonCamera camera;
30
+
31
+    public NikonCloseSessionAction(NikonCamera camera) {
32
+        this.camera = camera;
33
+    }
34
+
35
+    @Override
36
+    public void exec(IO io) {
37
+        SetDevicePropValueCommand setRecordingMedia = new SetDevicePropValueCommand(camera,
38
+                Property.NikonRecordingMedia, 0,
39
+                Datatype.uint8);
40
+        io.handleCommand(setRecordingMedia);
41
+
42
+        if (setRecordingMedia.getResponseCode() == Response.DeviceBusy) {
43
+            camera.onDeviceBusy(this, true);
44
+            return;
45
+        }
46
+
47
+        io.handleCommand(new CloseSessionCommand(camera));
48
+        camera.onSessionClosed();
49
+    }
50
+
51
+    @Override
52
+    public void reset() {
53
+    }
54
+}

+ 29 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonCommand.java

@@ -0,0 +1,29 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import com.remoteyourcam.usb.ptp.NikonCamera;
19
+import com.remoteyourcam.usb.ptp.commands.Command;
20
+
21
+public abstract class NikonCommand extends Command {
22
+
23
+    protected NikonCamera camera;
24
+
25
+    public NikonCommand(NikonCamera camera) {
26
+        super(camera);
27
+        this.camera = camera;
28
+    }
29
+}

+ 76 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonEventCheckCommand.java

@@ -0,0 +1,76 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import android.util.Log;
21
+
22
+import com.remoteyourcam.usb.AppConfig;
23
+import com.remoteyourcam.usb.ptp.NikonCamera;
24
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
25
+import com.remoteyourcam.usb.ptp.PtpConstants;
26
+import com.remoteyourcam.usb.ptp.PtpConstants.Event;
27
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
28
+
29
+public class NikonEventCheckCommand extends NikonCommand {
30
+
31
+    private static final String TAG = NikonEventCheckCommand.class.getSimpleName();
32
+
33
+    public NikonEventCheckCommand(NikonCamera camera) {
34
+        super(camera);
35
+    }
36
+
37
+    @Override
38
+    public void exec(IO io) {
39
+        io.handleCommand(this);
40
+    }
41
+
42
+    @Override
43
+    public void encodeCommand(ByteBuffer b) {
44
+        encodeCommand(b, Operation.NikonGetEvent);
45
+    }
46
+
47
+    @Override
48
+    protected void decodeData(ByteBuffer b, int length) {
49
+        int count = b.getShort();
50
+
51
+        while (count > 0) {
52
+            --count;
53
+
54
+            int eventCode = b.getShort();
55
+            int eventParam = b.getInt();
56
+
57
+            if (AppConfig.LOG) {
58
+                Log.i(TAG,
59
+                        String.format("event %s value %s(%04x)", PtpConstants.eventToString(eventCode),
60
+                                PtpConstants.propertyToString(eventParam), eventParam));
61
+            }
62
+
63
+            switch (eventCode) {
64
+            case Event.ObjectAdded:
65
+                camera.onEventObjectAdded(eventParam);
66
+                break;
67
+            case Event.DevicePropChanged:
68
+                camera.onEventDevicePropChanged(eventParam);
69
+                break;
70
+            case Event.CaptureComplete:
71
+                camera.onEventCaptureComplete();
72
+                break;
73
+            }
74
+        }
75
+    }
76
+}

+ 70 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonGetLiveViewImageAction.java

@@ -0,0 +1,70 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import com.remoteyourcam.usb.ptp.NikonCamera;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
21
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
23
+import com.remoteyourcam.usb.ptp.commands.SimpleCommand;
24
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
25
+
26
+public class NikonGetLiveViewImageAction implements PtpAction {
27
+
28
+    private final NikonCamera camera;
29
+    private final LiveViewData reuse;
30
+
31
+    public NikonGetLiveViewImageAction(NikonCamera camera, LiveViewData reuse) {
32
+        this.camera = camera;
33
+        this.reuse = reuse;
34
+    }
35
+
36
+    @Override
37
+    public void exec(IO io) {
38
+        SimpleCommand simpleCmd = new SimpleCommand(camera, Operation.NikonStartLiveView);
39
+        io.handleCommand(simpleCmd);
40
+
41
+        if (simpleCmd.getResponseCode() != Response.Ok) {
42
+            return;
43
+        }
44
+
45
+        SimpleCommand deviceReady = new SimpleCommand(camera, Operation.NikonDeviceReady);
46
+        for (int i = 0; i < 10; ++i) {
47
+            try {
48
+                Thread.sleep(300);
49
+            } catch (InterruptedException e) {
50
+                // nop
51
+            }
52
+
53
+            deviceReady.reset();
54
+            io.handleCommand(deviceReady);
55
+            if (deviceReady.getResponseCode() == Response.DeviceBusy) {
56
+                // still waiting
57
+            } else if (deviceReady.getResponseCode() == Response.Ok) {
58
+                camera.onLiveViewRestarted();
59
+                io.handleCommand(new NikonGetLiveViewImageCommand(camera, reuse));
60
+                return;
61
+            } else {
62
+                return;
63
+            }
64
+        }
65
+    }
66
+
67
+    @Override
68
+    public void reset() {
69
+    }
70
+}

+ 169 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonGetLiveViewImageCommand.java

@@ -0,0 +1,169 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import java.nio.ByteBuffer;
19
+import java.nio.ByteOrder;
20
+
21
+import org.acra.ErrorReporter;
22
+
23
+import android.graphics.BitmapFactory;
24
+import android.graphics.BitmapFactory.Options;
25
+import android.util.Log;
26
+
27
+import com.remoteyourcam.usb.AppConfig;
28
+import com.remoteyourcam.usb.ptp.NikonCamera;
29
+import com.remoteyourcam.usb.ptp.PacketUtil;
30
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
31
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
32
+import com.remoteyourcam.usb.ptp.PtpConstants.Product;
33
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
34
+import com.remoteyourcam.usb.ptp.model.LiveViewData;
35
+
36
+public class NikonGetLiveViewImageCommand extends NikonCommand {
37
+
38
+    private static boolean haveAddedDumpToAcra = false;
39
+
40
+    private static final String TAG = NikonGetLiveViewImageCommand.class.getSimpleName();
41
+    private static byte[] tmpStorage = new byte[0x4000];
42
+    private final Options options;
43
+    private LiveViewData data;
44
+
45
+    public NikonGetLiveViewImageCommand(NikonCamera camera, LiveViewData data) {
46
+        super(camera);
47
+        this.data = data;
48
+        if (data == null) {
49
+            this.data = new LiveViewData();
50
+            //this.data.histogram = ByteBuffer.allocate(1024 * 4);
51
+            //this.data.histogram.order(ByteOrder.LITTLE_ENDIAN);
52
+        } else {
53
+            this.data = data;
54
+        }
55
+        options = new BitmapFactory.Options();
56
+        options.inBitmap = this.data.bitmap;
57
+        options.inSampleSize = 1;
58
+        options.inTempStorage = tmpStorage;
59
+        this.data.bitmap = null;
60
+    }
61
+
62
+    @Override
63
+    public void exec(IO io) {
64
+        if (!camera.isLiveViewOpen()) {
65
+            return;
66
+        }
67
+        io.handleCommand(this);
68
+        if (responseCode == Response.DeviceBusy) {
69
+            camera.onDeviceBusy(this, true);
70
+            return;
71
+        }
72
+        data.hasHistogram = false;
73
+        if (this.data.bitmap != null && responseCode == Response.Ok) {
74
+            camera.onLiveViewReceived(data);
75
+        } else {
76
+            camera.onLiveViewReceived(null);
77
+        }
78
+    }
79
+
80
+    @Override
81
+    public void encodeCommand(ByteBuffer b) {
82
+        encodeCommand(b, Operation.NikonGetLiveViewImage);
83
+    }
84
+
85
+    @Override
86
+    protected void decodeData(ByteBuffer b, int length) {
87
+        if (length <= 128) {
88
+            return;
89
+        }
90
+
91
+        data.hasAfFrame = false;
92
+
93
+        int productId = camera.getProductId();
94
+        int start = b.position();
95
+        int pictureOffset;
96
+
97
+        switch (productId) {
98
+        case Product.NikonD5000:
99
+        case Product.NikonD3S:
100
+        case Product.NikonD90:
101
+            pictureOffset = 128;
102
+            break;
103
+        case Product.NikonD3X:
104
+        case Product.NikonD300S:
105
+        case Product.NikonD3:
106
+        case Product.NikonD300:
107
+        case Product.NikonD700:
108
+            pictureOffset = 64;
109
+            break;
110
+        case Product.NikonD7000:
111
+        case Product.NikonD5100:
112
+            pictureOffset = 384;
113
+            break;
114
+        default:
115
+            if (AppConfig.USE_ACRA && !haveAddedDumpToAcra) {
116
+                try {
117
+                    haveAddedDumpToAcra = true;
118
+                    String hex = PacketUtil.hexDumpToString(b.array(), start, length < 728 ? length : 728);
119
+                    ErrorReporter.getInstance().putCustomData("liveview hexdump", hex);
120
+                } catch (Throwable e) {
121
+                    // no fail
122
+                }
123
+            }
124
+            return;
125
+        }
126
+
127
+        b.order(ByteOrder.BIG_ENDIAN);
128
+
129
+        // read af frame
130
+        {
131
+            data.hasAfFrame = true;
132
+
133
+            int jpegImageWidth = b.getShort() & 0xFFFF;
134
+            int jpegImageHeight = b.getShort() & 0xFFFF;
135
+            int wholeWidth = b.getShort() & 0xFFFF;
136
+            int wholeHeight = b.getShort() & 0xFFFF;
137
+
138
+            float multX = jpegImageWidth / (float) wholeWidth;
139
+            float multY = jpegImageHeight / (float) wholeHeight;
140
+
141
+            b.position(start + 16);
142
+            data.nikonWholeWidth = wholeWidth;
143
+            data.nikonWholeHeight = wholeHeight;
144
+            data.nikonAfFrameWidth = (int) ((b.getShort() & 0xFFFF) * multX);
145
+            data.nikonAfFrameHeight = (int) ((b.getShort() & 0xFFFF) * multY);
146
+            data.nikonAfFrameCenterX = (int) ((b.getShort() & 0xFFFF) * multX);
147
+            data.nikonAfFrameCenterY = (int) ((b.getShort() & 0xFFFF) * multY);
148
+        }
149
+
150
+        b.order(ByteOrder.LITTLE_ENDIAN);
151
+
152
+        b.position(start + pictureOffset);
153
+
154
+        if (b.remaining() <= 128) {
155
+            data.bitmap = null;
156
+            return;
157
+        }
158
+
159
+        try {
160
+            data.bitmap = BitmapFactory.decodeByteArray(b.array(), b.position(), length - b.position(), options);
161
+        } catch (RuntimeException e) {
162
+            Log.e(TAG, "decoding failed " + e.toString());
163
+            Log.e(TAG, e.getLocalizedMessage());
164
+            if (AppConfig.LOG) {
165
+                PacketUtil.logHexdump(TAG, b.array(), start, 512);
166
+            }
167
+        }
168
+    }
169
+}

+ 51 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonGetVendorPropCodesCommand.java

@@ -0,0 +1,51 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.NikonCamera;
21
+import com.remoteyourcam.usb.ptp.PacketUtil;
22
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+
25
+public class NikonGetVendorPropCodesCommand extends NikonCommand {
26
+
27
+    private int[] propertyCodes = new int[0];
28
+
29
+    public NikonGetVendorPropCodesCommand(NikonCamera camera) {
30
+        super(camera);
31
+    }
32
+
33
+    public int[] getPropertyCodes() {
34
+        return propertyCodes;
35
+    }
36
+
37
+    @Override
38
+    public void exec(IO io) {
39
+        throw new UnsupportedOperationException();
40
+    }
41
+
42
+    @Override
43
+    public void encodeCommand(ByteBuffer b) {
44
+        encodeCommand(b, Operation.NikonGetVendorPropCodes);
45
+    }
46
+
47
+    @Override
48
+    protected void decodeData(ByteBuffer b, int length) {
49
+        propertyCodes = PacketUtil.readU16Array(b);
50
+    }
51
+}

+ 69 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonOpenSessionAction.java

@@ -0,0 +1,69 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import com.remoteyourcam.usb.ptp.NikonCamera;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
21
+import com.remoteyourcam.usb.ptp.PtpConstants;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Datatype;
23
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
24
+import com.remoteyourcam.usb.ptp.PtpConstants.Property;
25
+import com.remoteyourcam.usb.ptp.commands.OpenSessionCommand;
26
+import com.remoteyourcam.usb.ptp.commands.SetDevicePropValueCommand;
27
+
28
+public class NikonOpenSessionAction implements PtpAction {
29
+
30
+    private final NikonCamera camera;
31
+
32
+    public NikonOpenSessionAction(NikonCamera camera) {
33
+        this.camera = camera;
34
+    }
35
+
36
+    @Override
37
+    public void exec(IO io) {
38
+        OpenSessionCommand openSession = new OpenSessionCommand(camera);
39
+        io.handleCommand(openSession);
40
+        if (openSession.getResponseCode() == PtpConstants.Response.Ok) {
41
+            if (camera.hasSupportForOperation(Operation.NikonGetVendorPropCodes)) {
42
+                NikonGetVendorPropCodesCommand getPropCodes = new NikonGetVendorPropCodesCommand(camera);
43
+                io.handleCommand(getPropCodes);
44
+                SetDevicePropValueCommand c = new SetDevicePropValueCommand(camera, Property.NikonRecordingMedia, 1,
45
+                        Datatype.uint8);
46
+                io.handleCommand(c);
47
+                if (getPropCodes.getResponseCode() == PtpConstants.Response.Ok
48
+                        && c.getResponseCode() == PtpConstants.Response.Ok) {
49
+                    camera.setVendorPropCodes(getPropCodes.getPropertyCodes());
50
+                    camera.onSessionOpened();
51
+                } else {
52
+                    camera.onPtpError(String.format(
53
+                            "Couldn't read device property codes! Open session command failed with error code \"%s\"",
54
+                            PtpConstants.responseToString(getPropCodes.getResponseCode())));
55
+                }
56
+            } else {
57
+                camera.onSessionOpened();
58
+            }
59
+        } else {
60
+            camera.onPtpError(String.format(
61
+                    "Couldn't open session! Open session command failed with error code \"%s\"",
62
+                    PtpConstants.responseToString(openSession.getResponseCode())));
63
+        }
64
+    }
65
+
66
+    @Override
67
+    public void reset() {
68
+    }
69
+}

+ 66 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonStartLiveViewAction.java

@@ -0,0 +1,66 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import com.remoteyourcam.usb.ptp.NikonCamera;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
21
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
23
+import com.remoteyourcam.usb.ptp.commands.SimpleCommand;
24
+
25
+public class NikonStartLiveViewAction implements PtpAction {
26
+
27
+    private final NikonCamera camera;
28
+
29
+    public NikonStartLiveViewAction(NikonCamera camera) {
30
+        this.camera = camera;
31
+    }
32
+
33
+    @Override
34
+    public void exec(IO io) {
35
+        SimpleCommand simpleCmd = new SimpleCommand(camera, Operation.NikonStartLiveView);
36
+        io.handleCommand(simpleCmd);
37
+
38
+        if (simpleCmd.getResponseCode() != Response.Ok) {
39
+            return;
40
+        }
41
+
42
+        SimpleCommand deviceReady = new SimpleCommand(camera, Operation.NikonDeviceReady);
43
+        for (int i = 0; i < 10; ++i) {
44
+            try {
45
+                Thread.sleep(300);
46
+            } catch (InterruptedException e) {
47
+                // nop
48
+            }
49
+
50
+            deviceReady.reset();
51
+            io.handleCommand(deviceReady);
52
+            if (deviceReady.getResponseCode() == Response.DeviceBusy) {
53
+                // still waiting
54
+            } else if (deviceReady.getResponseCode() == Response.Ok) {
55
+                camera.onLiveViewStarted();
56
+                return;
57
+            } else {
58
+                return;
59
+            }
60
+        }
61
+    }
62
+
63
+    @Override
64
+    public void reset() {
65
+    }
66
+}

+ 54 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/commands/nikon/NikonStopLiveViewAction.java

@@ -0,0 +1,54 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.commands.nikon;
17
+
18
+import com.remoteyourcam.usb.ptp.NikonCamera;
19
+import com.remoteyourcam.usb.ptp.PtpAction;
20
+import com.remoteyourcam.usb.ptp.PtpCamera.IO;
21
+import com.remoteyourcam.usb.ptp.PtpConstants.Operation;
22
+import com.remoteyourcam.usb.ptp.PtpConstants.Response;
23
+import com.remoteyourcam.usb.ptp.commands.SimpleCommand;
24
+
25
+public class NikonStopLiveViewAction implements PtpAction {
26
+
27
+    private final NikonCamera camera;
28
+    private final boolean notifyUser;
29
+
30
+    public NikonStopLiveViewAction(NikonCamera camera, boolean notifyUser) {
31
+        this.camera = camera;
32
+        this.notifyUser = notifyUser;
33
+    }
34
+
35
+    @Override
36
+    public void exec(IO io) {
37
+        SimpleCommand simpleCmd = new SimpleCommand(camera, Operation.NikonEndLiveView);
38
+        io.handleCommand(simpleCmd);
39
+
40
+        if (simpleCmd.getResponseCode() == Response.DeviceBusy) {
41
+            camera.onDeviceBusy(this, true);
42
+        } else {
43
+            if (notifyUser) {
44
+                camera.onLiveViewStopped();
45
+            } else {
46
+                camera.onLiveViewStoppedInternal();
47
+            }
48
+        }
49
+    }
50
+
51
+    @Override
52
+    public void reset() {
53
+    }
54
+}

+ 113 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/model/DeviceInfo.java

@@ -0,0 +1,113 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.model;
17
+
18
+import java.nio.ByteBuffer;
19
+import java.util.Arrays;
20
+
21
+import com.remoteyourcam.usb.ptp.PacketUtil;
22
+import com.remoteyourcam.usb.ptp.PtpConstants;
23
+
24
+/**
25
+ * Device info data set as defined by PTP standard.
26
+ */
27
+public class DeviceInfo {
28
+
29
+    public short standardVersion;
30
+    public int vendorExtensionId;
31
+    public short vendorExtensionVersion;
32
+    public String vendorExtensionDesc;
33
+    public short functionalMode;
34
+    public int[] operationsSupported;
35
+    public int[] eventsSupported;
36
+    public int[] devicePropertiesSupported;
37
+    public int[] captureFormats;
38
+    public int[] imageFormats;
39
+    public String manufacture;
40
+    public String model;
41
+    public String deviceVersion;
42
+    public String serialNumber;
43
+
44
+    public DeviceInfo(ByteBuffer b, int length) {
45
+        decode(b, length);
46
+    }
47
+
48
+    public DeviceInfo() {
49
+    }
50
+
51
+    public void decode(ByteBuffer b, int length) {
52
+        standardVersion = b.getShort();
53
+        vendorExtensionId = b.getInt();
54
+        vendorExtensionVersion = b.getShort();
55
+        vendorExtensionDesc = PacketUtil.readString(b);
56
+        functionalMode = b.getShort();
57
+        operationsSupported = PacketUtil.readU16Array(b);
58
+        eventsSupported = PacketUtil.readU16Array(b);
59
+        devicePropertiesSupported = PacketUtil.readU16Array(b);
60
+        captureFormats = PacketUtil.readU16Array(b);
61
+        imageFormats = PacketUtil.readU16Array(b);
62
+        manufacture = PacketUtil.readString(b);
63
+        model = PacketUtil.readString(b);
64
+        deviceVersion = PacketUtil.readString(b);
65
+        serialNumber = PacketUtil.readString(b);
66
+    }
67
+
68
+    public void encode(ByteBuffer b) {
69
+        b.putShort(standardVersion);
70
+        b.putInt(vendorExtensionId);
71
+        b.putInt(vendorExtensionVersion);
72
+        PacketUtil.writeString(b, "");
73
+        b.putShort(functionalMode);
74
+        PacketUtil.writeU16Array(b, new int[0]);
75
+        PacketUtil.writeU16Array(b, new int[0]);
76
+        PacketUtil.writeU16Array(b, new int[0]);
77
+        PacketUtil.writeU16Array(b, new int[0]);
78
+        PacketUtil.writeU16Array(b, new int[0]);
79
+        PacketUtil.writeString(b, "");
80
+        PacketUtil.writeString(b, "");
81
+        PacketUtil.writeString(b, "");
82
+    }
83
+
84
+    @Override
85
+    public String toString() {
86
+        // Changes here have to reflect changes in PtpConstants.main()
87
+        StringBuilder b = new StringBuilder();
88
+        b.append("DeviceInfo\n");
89
+        b.append("StandardVersion: ").append(standardVersion).append('\n');
90
+        b.append("VendorExtensionId: ").append(vendorExtensionId).append('\n');
91
+        b.append("VendorExtensionVersion: ").append(vendorExtensionVersion).append('\n');
92
+        b.append("VendorExtensionDesc: ").append(vendorExtensionDesc).append('\n');
93
+        b.append("FunctionalMode: ").append(functionalMode).append('\n');
94
+        appendU16Array(b, "OperationsSupported", PtpConstants.Operation.class, operationsSupported);
95
+        appendU16Array(b, "EventsSupported", PtpConstants.Event.class, eventsSupported);
96
+        appendU16Array(b, "DevicePropertiesSupported", PtpConstants.Property.class, devicePropertiesSupported);
97
+        appendU16Array(b, "CaptureFormats", PtpConstants.ObjectFormat.class, captureFormats);
98
+        appendU16Array(b, "ImageFormats", PtpConstants.ObjectFormat.class, imageFormats);
99
+        b.append("Manufacture: ").append(manufacture).append('\n');
100
+        b.append("Model: ").append(model).append('\n');
101
+        b.append("DeviceVersion: ").append(deviceVersion).append('\n');
102
+        b.append("SerialNumber: ").append(serialNumber).append('\n');
103
+        return b.toString();
104
+    }
105
+
106
+    private static void appendU16Array(StringBuilder b, String name, Class<?> cl, int[] a) {
107
+        Arrays.sort(a);
108
+        b.append(name).append(":\n");
109
+        for (int i = 0; i < a.length; ++i) {
110
+            b.append("    ").append(PtpConstants.constantToString(cl, a[i])).append('\n');
111
+        }
112
+    }
113
+}

+ 102 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/model/DevicePropDesc.java

@@ -0,0 +1,102 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.model;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PacketUtil;
21
+import com.remoteyourcam.usb.ptp.PtpConstants.Datatype;
22
+
23
+public class DevicePropDesc {
24
+
25
+    public int code;
26
+    public int datatype;
27
+    public boolean readOnly;
28
+    public int factoryDefault;
29
+    public int currentValue;
30
+    public int[] description;
31
+
32
+    public DevicePropDesc() {
33
+    }
34
+
35
+    public DevicePropDesc(ByteBuffer b, int length) {
36
+        decode(b, length);
37
+    }
38
+
39
+    public void decode(ByteBuffer b, int length) {
40
+        code = b.getShort() & 0xFFFF;
41
+        datatype = b.getShort() & 0xFFFF;
42
+        readOnly = b.get() == 0;
43
+
44
+        if (datatype == Datatype.int8 || datatype == Datatype.uint8) {
45
+            factoryDefault = b.get() & 0xFF;
46
+            currentValue = b.get() & 0xFF;
47
+            int form = b.get();
48
+            if (form == 2) {
49
+                description = PacketUtil.readU8Enumeration(b);
50
+            } else if (form == 1) {
51
+                int mini = b.get();
52
+                int maxi = b.get();
53
+                int step = b.get();
54
+                description = new int[(maxi - mini) / step + 1];
55
+                for (int i = 0; i < description.length; ++i) {
56
+                    description[i] = mini + step * i;
57
+                }
58
+            }
59
+        } else if (datatype == Datatype.uint16) {
60
+            factoryDefault = b.getShort() & 0xFFFF;
61
+            currentValue = b.getShort() & 0xFFFF;
62
+            int form = b.get();
63
+            if (form == 2) {
64
+                description = PacketUtil.readU16Enumeration(b);
65
+            } else if (form == 1) {
66
+                int mini = b.getShort() & 0xFFFF;
67
+                int maxi = b.getShort() & 0xFFFF;
68
+                int step = b.getShort() & 0xFFFF;
69
+                description = new int[(maxi - mini) / step + 1];
70
+                for (int i = 0; i < description.length; ++i) {
71
+                    description[i] = mini + step * i;
72
+                }
73
+            }
74
+        } else if (datatype == Datatype.int16) {
75
+            factoryDefault = b.getShort();
76
+            currentValue = b.getShort();
77
+            int form = b.get();
78
+            if (form == 2) {
79
+                description = PacketUtil.readS16Enumeration(b);
80
+            } else if (form == 1) {
81
+                int mini = b.getShort();
82
+                int maxi = b.getShort();
83
+                int step = b.getShort();
84
+                description = new int[(maxi - mini) / step + 1];
85
+                for (int i = 0; i < description.length; ++i) {
86
+                    description[i] = mini + step * i;
87
+                }
88
+            }
89
+        } else if (datatype == Datatype.int32 || datatype == Datatype.uint32) {
90
+            factoryDefault = b.getInt();
91
+            currentValue = b.getInt();
92
+            int form = b.get();
93
+            if (form == 2) {
94
+                description = PacketUtil.readU32Enumeration(b);
95
+            }
96
+        }
97
+
98
+        if (description == null) {
99
+            description = new int[0];
100
+        }
101
+    }
102
+}

+ 44 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/model/LiveViewData.java

@@ -0,0 +1,44 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.model;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import android.graphics.Bitmap;
21
+
22
+public class LiveViewData {
23
+
24
+    public Bitmap bitmap;
25
+
26
+    public int zoomFactor;
27
+    public int zoomRectLeft;
28
+    public int zoomRectTop;
29
+    public int zoomRectRight;
30
+    public int zoomRectBottom;
31
+
32
+    public boolean hasHistogram;
33
+    public ByteBuffer histogram;
34
+
35
+    // dimensions are in bitmap size
36
+    public boolean hasAfFrame;
37
+    public int nikonAfFrameCenterX;
38
+    public int nikonAfFrameCenterY;
39
+    public int nikonAfFrameWidth;
40
+    public int nikonAfFrameHeight;
41
+
42
+    public int nikonWholeWidth;
43
+    public int nikonWholeHeight;
44
+}

+ 101 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/model/ObjectInfo.java

@@ -0,0 +1,101 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.model;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PacketUtil;
21
+import com.remoteyourcam.usb.ptp.PtpConstants;
22
+
23
+/**
24
+ * Object info data set as defined by the PTP standard.
25
+ */
26
+public class ObjectInfo {
27
+
28
+    public int storageId;
29
+    public int objectFormat;
30
+    public int protectionStatus;
31
+    public int objectCompressedSize;
32
+    public int thumbFormat;
33
+    public int thumbCompressedSize;
34
+    public int thumbPixWidth;
35
+    public int thumbPixHeight;
36
+    public int imagePixWidth;
37
+    public int imagePixHeight;
38
+    public int imageBitDepth;
39
+    public int parentObject;
40
+    public int associationType;
41
+    public int associationDesc;
42
+    public int sequenceNumber;
43
+    public String filename;
44
+    public String captureDate;
45
+    public String modificationDate;
46
+    public int keywords;
47
+
48
+    public ObjectInfo() {
49
+    }
50
+
51
+    public ObjectInfo(ByteBuffer b, int length) {
52
+        decode(b, length);
53
+    }
54
+
55
+    public void decode(ByteBuffer b, int length) {
56
+        storageId = b.getInt();
57
+        objectFormat = b.getShort();
58
+        protectionStatus = b.getShort();
59
+        objectCompressedSize = b.getInt();
60
+        thumbFormat = b.getShort();
61
+        thumbCompressedSize = b.getInt();
62
+        thumbPixWidth = b.getInt();
63
+        thumbPixHeight = b.getInt();
64
+        imagePixWidth = b.getInt();
65
+        imagePixHeight = b.getInt();
66
+        imageBitDepth = b.getInt();
67
+        parentObject = b.getInt();
68
+        associationType = b.getShort();
69
+        associationDesc = b.getInt();
70
+        sequenceNumber = b.getInt();
71
+        filename = PacketUtil.readString(b);
72
+        captureDate = PacketUtil.readString(b);
73
+        modificationDate = PacketUtil.readString(b);
74
+        keywords = b.get(); // string, not used on camera?
75
+    }
76
+
77
+    @Override
78
+    public String toString() {
79
+        StringBuilder b = new StringBuilder();
80
+        b.append("ObjectInfo\n");
81
+        b.append("StorageId: ").append(String.format("0x%08x\n", storageId));
82
+        b.append("ObjectFormat: ").append(PtpConstants.objectFormatToString(objectFormat)).append('\n');
83
+        b.append("ProtectionStatus: ").append(protectionStatus).append('\n');
84
+        b.append("ObjectCompressedSize: ").append(objectCompressedSize).append('\n');
85
+        b.append("ThumbFormat: ").append(PtpConstants.objectFormatToString(thumbFormat)).append('\n');
86
+        b.append("ThumbCompressedSize: ").append(thumbCompressedSize).append('\n');
87
+        b.append("ThumbPixWdith: ").append(thumbPixWidth).append('\n');
88
+        b.append("ThumbPixHeight: ").append(thumbPixHeight).append('\n');
89
+        b.append("ImagePixWidth: ").append(imagePixWidth).append('\n');
90
+        b.append("ImagePixHeight: ").append(imagePixHeight).append('\n');
91
+        b.append("ImageBitDepth: ").append(imageBitDepth).append('\n');
92
+        b.append("ParentObject: ").append(String.format("0x%08x", parentObject)).append('\n');
93
+        b.append("AssociationType: ").append(associationType).append('\n');
94
+        b.append("AssociatonDesc: ").append(associationDesc).append('\n');
95
+        b.append("Filename: ").append(filename).append('\n');
96
+        b.append("CaptureDate: ").append(captureDate).append('\n');
97
+        b.append("ModificationDate: ").append(modificationDate).append('\n');
98
+        b.append("Keywords: ").append(keywords).append('\n');
99
+        return b.toString();
100
+    }
101
+}

+ 47 - 0
app/src/main/java/com/remoteyourcam/usb/ptp/model/StorageInfo.java

@@ -0,0 +1,47 @@
1
+/**
2
+ * Copyright 2013 Nils Assbeck, Guersel Ayaz and Michael Zoech
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ *     http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+package com.remoteyourcam.usb.ptp.model;
17
+
18
+import java.nio.ByteBuffer;
19
+
20
+import com.remoteyourcam.usb.ptp.PacketUtil;
21
+
22
+public class StorageInfo {
23
+
24
+    public int storageType;
25
+    public int filesystemType;
26
+    public int accessCapability;
27
+    public long maxCapacity;
28
+    public long freeSpaceInBytes;
29
+    public int freeSpaceInImages;
30
+    public String storageDescription;
31
+    public String volumeLabel;
32
+
33
+    public StorageInfo(ByteBuffer b, int length) {
34
+        decode(b, length);
35
+    }
36
+
37
+    private void decode(ByteBuffer b, int length) {
38
+        storageType = b.getShort() & 0xffff;
39
+        filesystemType = b.getShort() & 0xffff;
40
+        accessCapability = b.getShort() & 0xff;
41
+        maxCapacity = b.getLong();
42
+        freeSpaceInBytes = b.getLong();
43
+        freeSpaceInImages = b.getInt();
44
+        storageDescription = PacketUtil.readString(b);
45
+        volumeLabel = PacketUtil.readString(b);
46
+    }
47
+}

pai2 - Gogs: Go Git Service

拍爱

Brightcells: 7a17d0fb90 add api wxpay & add redis relative 10 ans auparavant
..
migrations 4defb80fdc gogs first init 10 ans auparavant
__init__.py 4defb80fdc gogs first init 10 ans auparavant
admin.py 4defb80fdc gogs first init 10 ans auparavant
models.py 4defb80fdc gogs first init 10 ans auparavant
tests.py 4defb80fdc gogs first init 10 ans auparavant
urls.py 7a17d0fb90 add api wxpay & add redis relative 10 ans auparavant
views.py 4defb80fdc gogs first init 10 ans auparavant