Skip to content
Snippets Groups Projects
Commit 1fa8c062 authored by Aline Bonnet's avatar Aline Bonnet Committed by gerrit2
Browse files

vcard: send vcard during a call

When a user starts a call on Android, his profil is sent with a vcard.
- DRingService implements sendProfil that cuts the vcard in blocks of 1000 bytes.
- there are new methods in VCardUtils to save the vcard without a string. The
photo is saved without new line now because the other client can't read the old vcard.

Change-Id: I56eecd73f82b0e313137e47c1a430a3180c1558c
Tuleap: #946
parent 30e7b777
Branches
Tags
No related merge requests found
/**
* Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
* Copyright (C) 2004-2016 Savoir-faire Linux Inc.
*
* <p>
* Author: Regis Montoya <r3gis.3R@gmail.com>
* Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
* Alexandre Lision <alexandre.lision@savoirfairelinux.com>
* Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
......@@ -14,24 +14,36 @@
* If you own a pjsip commercial license you can also redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as an android library.
*
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cx.ring.service;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;
import java.io.IOException;
import java.lang.ref.WeakReference;
......@@ -40,20 +52,13 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Service;
import android.content.Intent;
import android.os.*;
import android.util.Log;
import java.util.Random;
import cx.ring.BuildConfig;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager;
import cx.ring.model.Codec;
import cx.ring.utils.SwigNativeConverter;
import cx.ring.utils.VCardUtils;
import ezvcard.VCard;
public class DRingService extends Service {
......@@ -64,6 +69,7 @@ public class DRingService extends Service {
static public final String DRING_CONNECTION_CHANGED = BuildConfig.APPLICATION_ID + ".event.DRING_CONNECTION_CHANGE";
static public final String VIDEO_EVENT = BuildConfig.APPLICATION_ID + ".event.VIDEO_EVENT";
private static final int VCARD_CHUNK_SIZE = 1000;
private Handler handler = new Handler();
private static int POLLING_TIMEOUT = 50;
......@@ -91,7 +97,7 @@ public class DRingService extends Service {
int w, h;
boolean mixer;
long window = 0;
};
}
static public WeakReference<SurfaceHolder> mCameraPreviewSurface = new WeakReference<>(null);
static public Map<String, WeakReference<SurfaceHolder>> videoSurfaces = Collections.synchronizedMap(new HashMap<String, WeakReference<SurfaceHolder>>());
......@@ -164,18 +170,18 @@ public class DRingService extends Service {
return mExecutor;
}
public void decodingStarted(String id, String shm_path, int w, int h, boolean is_mixer) {
Log.i(TAG, "DRingService.decodingStarted() " + id + " " + w + "x" + h);
public void decodingStarted(String id, String shmPath, int width, int height, boolean isMixer) {
Log.i(TAG, "DRingService.decodingStarted() " + id + " " + width + "x" + height);
Shm shm = new Shm();
shm.id = id;
shm.path = shm_path;
shm.w = w;
shm.h = h;
shm.mixer = is_mixer;
shm.path = shmPath;
shm.w = width;
shm.h = height;
shm.mixer = isMixer;
videoInputs.put(id, shm);
WeakReference<SurfaceHolder> w_holder = videoSurfaces.get(id);
if (w_holder != null) {
SurfaceHolder holder = w_holder.get();
WeakReference<SurfaceHolder> weakSurfaceHolder = videoSurfaces.get(id);
if (weakSurfaceHolder != null) {
SurfaceHolder holder = weakSurfaceHolder.get();
if (holder != null)
startVideo(shm, holder);
}
......@@ -231,13 +237,6 @@ public class DRingService extends Service {
this.height = height;
this.rate = rate;
}
public VideoParams(VideoParams p) {
this.id = p.id;
this.format = p.format;
this.width = p.width;
this.height = p.height;
this.rate = p.rate;
}
public int id;
public int format;
......@@ -247,37 +246,41 @@ public class DRingService extends Service {
public int height;
//size, rotated, as seen by the daemon
public int rot_width;
public int rot_height;
public int rotWidth;
public int rotHeight;
public int rate;
public int rotation;
}
static public int rotationToDegrees(int r) {
switch (r) {
case Surface.ROTATION_0: return 0;
case Surface.ROTATION_90: return 90;
case Surface.ROTATION_180: return 180;
case Surface.ROTATION_270: return 270;
static public int rotationToDegrees(int rotation) {
switch (rotation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
return 0;
}
public void setVideoRotation(VideoParams p, Camera.CameraInfo info) {
public void setVideoRotation(VideoParams videoParams, Camera.CameraInfo info) {
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
int rotation = rotationToDegrees(windowManager.getDefaultDisplay().getRotation());
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
p.rotation = (info.orientation + rotation + 360) % 360;
videoParams.rotation = (info.orientation + rotation + 360) % 360;
} else {
p.rotation = (info.orientation - rotation + 360) % 360;
videoParams.rotation = (info.orientation - rotation + 360) % 360;
}
}
public void setCameraDisplayOrientation(int cam_id, android.hardware.Camera camera) {
public void setCameraDisplayOrientation(int camId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cam_id, info);
android.hardware.Camera.getCameraInfo(camId, info);
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
int rotation = rotationToDegrees(windowManager.getDefaultDisplay().getRotation());
int result;
......@@ -290,29 +293,29 @@ public class DRingService extends Service {
camera.setDisplayOrientation(result);
}
public void startCapture(final VideoParams p) {
public void startCapture(final VideoParams videoParams) {
stopCapture();
SurfaceHolder surface = mCameraPreviewSurface.get();
if (surface == null) {
Log.w(TAG, "Can't start capture: no surface registered.");
previewParams = p;
previewParams = videoParams;
Intent intent = new Intent(VIDEO_EVENT);
intent.putExtra("start", true);
sendBroadcast(intent);
return;
}
if (p == null) {
if (videoParams == null) {
Log.w(TAG, "startCapture: no video parameters ");
return;
}
Log.d(TAG, "startCapture " + p.id);
Log.d(TAG, "startCapture " + videoParams.id);
final Camera preview;
try {
preview = Camera.open(p.id);
setCameraDisplayOrientation(p.id, preview);
preview = Camera.open(videoParams.id);
setCameraDisplayOrientation(videoParams.id, preview);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
return;
......@@ -327,11 +330,11 @@ public class DRingService extends Service {
}
Camera.Parameters parameters = preview.getParameters();
parameters.setPreviewFormat(p.format);
parameters.setPreviewSize(p.width, p.height);
parameters.setPreviewFormat(videoParams.format);
parameters.setPreviewSize(videoParams.width, videoParams.height);
for (int[] fps : parameters.getSupportedPreviewFpsRange()) {
if (p.rate >= fps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] &&
p.rate <= fps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]) {
if (videoParams.rate >= fps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] &&
videoParams.rate <= fps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]) {
parameters.setPreviewFpsRange(fps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
fps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
}
......@@ -340,15 +343,16 @@ public class DRingService extends Service {
try {
preview.setParameters(parameters);
} catch (RuntimeException e) {
Log.e(TAG, e.getMessage());
Log.e(TAG, "Error while settings preview parameters", e);
}
preview.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
long ptr = RingserviceJNI.obtainFrame(data.length);
if (ptr != 0)
RingserviceJNI.setVideoFrame(data, data.length, ptr, p.width, p.height, p.rotation);
if (ptr != 0) {
RingserviceJNI.setVideoFrame(data, data.length, ptr, videoParams.width, videoParams.height, videoParams.rotation);
}
RingserviceJNI.releaseFrame(ptr);
}
});
......@@ -356,20 +360,21 @@ public class DRingService extends Service {
@Override
public void onError(int error, Camera cam) {
Log.w(TAG, "Camera onError " + error);
if (preview == cam)
if (preview == cam) {
stopCapture();
}
}
});
preview.startPreview();
previewCamera = preview;
previewParams = p;
previewParams = videoParams;
Intent intent = new Intent(VIDEO_EVENT);
intent.putExtra("camera", p.id == 1);
intent.putExtra("camera", videoParams.id == 1);
intent.putExtra("started", true);
intent.putExtra("width", p.rot_width);
intent.putExtra("height", p.rot_height);
intent.putExtra("width", videoParams.rotWidth);
intent.putExtra("height", videoParams.rotHeight);
sendBroadcast(intent);
}
......@@ -435,6 +440,7 @@ public class DRingService extends Service {
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, 0);
}
public final <T> T executeAndReturn(final SipRunnableWithReturn<T> r) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
......@@ -445,8 +451,9 @@ public class DRingService extends Service {
}
BlockingRunnable br = new BlockingRunnable(r);
if (!br.postAndWait(this, 0))
if (!br.postAndWait(this, 0)) {
throw new RuntimeException("Can't execute runnable");
}
return r.getVal();
}
......@@ -463,7 +470,7 @@ public class DRingService extends Service {
try {
mTask.run();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Error in Blocking Runnable task " + mTask.toString(), e);
} finally {
synchronized (this) {
mDone = true;
......@@ -488,6 +495,7 @@ public class DRingService extends Service {
try {
wait(delay);
} catch (InterruptedException ex) {
Log.e(TAG, "Error in postAndWait", ex);
}
}
} else {
......@@ -495,6 +503,7 @@ public class DRingService extends Service {
try {
wait();
} catch (InterruptedException ex) {
Log.e(TAG, "Error in postAndWait", ex);
}
}
}
......@@ -527,7 +536,6 @@ public class DRingService extends Service {
try {
System.loadLibrary("ring");
isPjSipStackStarted = true;
} catch (UnsatisfiedLinkError e) {
Log.e(TAG, "Problem with the current Pj stack...", e);
isPjSipStackStarted = false;
......@@ -572,8 +580,8 @@ public class DRingService extends Service {
doRun();
} catch (SameThreadException e) {
Log.e(TAG, "Not done from same thread");
} catch (RemoteException e) {
Log.e(TAG, e.toString());
} catch (RemoteException ex) {
Log.e(TAG, ex.getMessage(), ex);
}
}
}
......@@ -590,10 +598,11 @@ public class DRingService extends Service {
@Override
public void run() {
try {
if (isPjSipStackStarted)
if (isPjSipStackStarted) {
obj = doRun();
else
} else {
Log.e(TAG, "Can't perform operation: daemon not started.");
}
//done = true;
} catch (SameThreadException e) {
Log.e(TAG, "Not done from same thread");
......@@ -626,16 +635,18 @@ public class DRingService extends Service {
protected final IDRingService.Stub mBinder = new IDRingService.Stub() {
@Override
public String placeCall(final String account, final String number, final boolean video) {
return getExecutor().executeAndReturn(new SipRunnableWithReturn<String>() {
@Override
protected String doRun() throws SameThreadException {
Log.i(TAG, "DRingService.placeCall() thread running... " + number + " video: " + video);
String call_id = Ringservice.placeCall(account, number);
if (!video)
Ringservice.muteLocalMedia(call_id, "MEDIA_TYPE_VIDEO", true);
return call_id;
String callId = Ringservice.placeCall(account, number);
if (!video) {
Ringservice.muteLocalMedia(callId, "MEDIA_TYPE_VIDEO", true);
}
return callId;
}
});
}
......@@ -698,6 +709,39 @@ public class DRingService extends Service {
});
}
@Override
public void sendProfile(final String callID) {
getExecutor().execute(new SipRunnable() {
@Override
protected void doRun() throws SameThreadException, RemoteException {
final String ringProfileVCardMime = "x-ring/ring.profile.vcard";
VCard vcard = VCardUtils.loadLocalProfileFromDisk(DRingService.this);
String stringVCard = VCardUtils.vcardToString(vcard);
int nbTotal = stringVCard.length() / VCARD_CHUNK_SIZE + (stringVCard.length() % VCARD_CHUNK_SIZE != 0 ? 1 : 0);
int i = 1;
Random r = new Random(System.currentTimeMillis());
int key = r.nextInt();
Log.d(TAG, "sendProfile, vcard " + stringVCard);
while (i <= nbTotal) {
HashMap<String, String> chunk = new HashMap<>();
Log.d(TAG, "lenght vcard " + stringVCard.length() + " id " + key + " part " + i + " nbTotal " + nbTotal);
String keyHashMap = ringProfileVCardMime + "; id=" + key + ",part=" + i + ",of=" + nbTotal;
String message = stringVCard.substring(0, Math.min(VCARD_CHUNK_SIZE, stringVCard.length()));
chunk.put(keyHashMap, message);
if (stringVCard.length() > VCARD_CHUNK_SIZE) {
stringVCard = stringVCard.substring(VCARD_CHUNK_SIZE);
}
i++;
Ringservice.sendTextMessage(callID, StringMap.toSwig(chunk), "Me", false);
}
}
});
}
@Override
public boolean isStarted() throws RemoteException {
return isPjSipStackStarted;
......@@ -890,9 +934,10 @@ public class DRingService extends Service {
Intent intent = new Intent(CallManagerCallBack.CALL_STATE_CHANGED);
intent.putExtra("com.savoirfairelinux.sflphone.service.newstate", bundle);
sendBroadcast(intent);
} else
} else {
Log.i(TAG, "NOT OK");
}
}
});
}
......@@ -905,9 +950,10 @@ public class DRingService extends Service {
Log.i(TAG, "DRingService.attendedTransfer() thread running...");
if (Ringservice.attendedTransfer(transferID, targetID)) {
Log.i(TAG, "OK");
} else
} else {
Log.i(TAG, "NOT OK");
}
}
});
}
......@@ -929,12 +975,12 @@ public class DRingService extends Service {
}
@Override
public void joinParticipant(final String sel_callID, final String drag_callID) throws RemoteException {
public void joinParticipant(final String selCallID, final String dragCallID) throws RemoteException {
getExecutor().execute(new SipRunnable() {
@Override
protected void doRun() throws SameThreadException, RemoteException {
Log.i(TAG, "DRingService.joinParticipant() thread running...");
Ringservice.joinParticipant(sel_callID, drag_callID);
Ringservice.joinParticipant(selCallID, dragCallID);
// Generate a CONF_CREATED callback
}
});
......@@ -978,12 +1024,12 @@ public class DRingService extends Service {
}
@Override
public void joinConference(final String sel_confID, final String drag_confID) throws RemoteException {
public void joinConference(final String selConfID, final String dragConfID) throws RemoteException {
getExecutor().execute(new SipRunnable() {
@Override
protected void doRun() throws SameThreadException, RemoteException {
Log.i(TAG, "DRingService.joinConference() thread running...");
Ringservice.joinConference(sel_confID, drag_confID);
Ringservice.joinConference(selConfID, dragConfID);
}
});
......@@ -1043,19 +1089,20 @@ public class DRingService extends Service {
@Override
protected Map<String, ArrayList<String>> doRun() throws SameThreadException {
Log.i(TAG, "DRingService.getConferenceList() thread running...");
StringVect call_ids = Ringservice.getCallList();
HashMap<String, ArrayList<String>> confs = new HashMap<>(call_ids.size());
for (int i=0; i<call_ids.size(); i++) {
String call_id = call_ids.get(i);
String conf_id = Ringservice.getConferenceId(call_id);
if (conf_id == null || conf_id.isEmpty())
conf_id = call_id;
ArrayList<String> calls = confs.get(conf_id);
StringVect callIds = Ringservice.getCallList();
HashMap<String, ArrayList<String>> confs = new HashMap<>(callIds.size());
for (int i = 0; i < callIds.size(); i++) {
String callId = callIds.get(i);
String confId = Ringservice.getConferenceId(callId);
if (confId == null || confId.isEmpty()) {
confId = callId;
}
ArrayList<String> calls = confs.get(confId);
if (calls == null) {
calls = new ArrayList<>();
confs.put(conf_id, calls);
confs.put(confId, calls);
}
calls.add(call_id);
calls.add(callId);
}
return confs;
}
......@@ -1180,113 +1227,30 @@ public class DRingService extends Service {
Log.i(TAG, "DRingService.getCodecList() thread running...");
ArrayList<Codec> results = new ArrayList<>();
UintVect active_payloads = Ringservice.getActiveCodecList(accountID);
for (int i = 0; i < active_payloads.size(); ++i) {
Log.i(TAG, "DRingService.getCodecDetails(" + accountID +", "+ active_payloads.get(i) +")");
results.add(new Codec(active_payloads.get(i), Ringservice.getCodecDetails(accountID, active_payloads.get(i)), true));
UintVect activePayloads = Ringservice.getActiveCodecList(accountID);
for (int i = 0; i < activePayloads.size(); ++i) {
Log.i(TAG, "DRingService.getCodecDetails(" + accountID + ", " + activePayloads.get(i) + ")");
results.add(new Codec(activePayloads.get(i), Ringservice.getCodecDetails(accountID, activePayloads.get(i)), true));
}
UintVect payloads = Ringservice.getCodecList();
cl : for (int i = 0; i < payloads.size(); ++i) {
cl:
for (int i = 0; i < payloads.size(); ++i) {
for (Codec co : results)
if (co.getPayload() == payloads.get(i))
continue cl;
StringMap details = Ringservice.getCodecDetails(accountID, payloads.get(i));
if (details.size() > 1)
if (details.size() > 1) {
results.add(new Codec(payloads.get(i), details, false));
else
} else {
Log.i(TAG, "Error loading codec " + i);
}
}
return results;
}
});
}
/*
@Override
public Map getRingtoneList() throws RemoteException {
class RingtoneList extends SipRunnableWithReturn {
@Override
protected StringMap doRun() throws SameThreadException {
Log.i(TAG, "DRingService.getRingtoneList() thread running...");
return Ringservice.getR();
}
}
RingtoneList runInstance = new RingtoneList();
getExecutor().execute(runInstance);
while (!runInstance.isDone()) {
}
StringMap ringtones = (StringMap) runInstance.getVal();
for (int i = 0; i < ringtones.size(); ++i) {
// Log.i(TAG,"ringtones "+i+" "+ ringtones.);
}
return null;
}
@Override
public boolean checkForPrivateKey(final String pemPath) throws RemoteException {
class hasPrivateKey extends SipRunnableWithReturn {
@Override
protected Boolean doRun() throws SameThreadException {
Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
return Ringservice.sflph_config_check_for_private_key(pemPath);
}
}
hasPrivateKey runInstance = new hasPrivateKey();
getExecutor().execute(runInstance);
while (!runInstance.isDone()) {
}
return (Boolean) runInstance.getVal();
}
@Override
public boolean checkCertificateValidity(final String pemPath) throws RemoteException {
class isValid extends SipRunnableWithReturn {
@Override
protected Boolean doRun() throws SameThreadException {
Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
return Ringservice.sflph_config_check_certificate_validity(pemPath, pemPath);
}
}
isValid runInstance = new isValid();
getExecutor().execute(runInstance);
while (!runInstance.isDone()) {
}
return (Boolean) runInstance.getVal();
}
@Override
public boolean checkHostnameCertificate(final String certificatePath, final String host, final String port) throws RemoteException {
class isValid extends SipRunnableWithReturn {
@Override
protected Boolean doRun() throws SameThreadException {
Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
return Ringservice.sflph_config_check_hostname_certificate(host, port);
}
}
isValid runInstance = new isValid();
getExecutor().execute(runInstance);
while (!runInstance.isDone()) {
}
return (Boolean) runInstance.getVal();
}
*/
@Override
public Map<String, String> validateCertificatePath(final String accountID, final String certificatePath, final String privateKeyPath, final String privateKeyPass) throws RemoteException {
return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
......@@ -1434,8 +1398,7 @@ public class DRingService extends Service {
});
}
public void videoSurfaceAdded(String id)
{
public void videoSurfaceAdded(String id) {
Log.d(TAG, "DRingService.videoSurfaceAdded() " + id);
Shm shm = videoInputs.get(id);
SurfaceHolder holder = videoSurfaces.get(id).get();
......@@ -1443,8 +1406,7 @@ public class DRingService extends Service {
startVideo(shm, holder);
}
public void videoSurfaceRemoved(String id)
{
public void videoSurfaceRemoved(String id) {
Log.d(TAG, "DRingService.videoSurfaceRemoved() " + id);
Shm shm = videoInputs.get(id);
if (shm != null)
......@@ -1465,10 +1427,10 @@ public class DRingService extends Service {
getExecutor().execute(new SipRunnable() {
@Override
protected void doRun() throws SameThreadException, RemoteException {
int cam_id = (front ? videoManagerCallback.cameraFront : videoManagerCallback.cameraBack);
String uri = "camera://" + cam_id;
int camId = (front ? videoManagerCallback.cameraFront : videoManagerCallback.cameraBack);
String uri = "camera://" + camId;
Log.i(TAG, "DRingService.switchInput() " + uri);
Ringservice.applySettings(id, videoManagerCallback.getNativeParams(cam_id).toMap(getResources().getConfiguration().orientation));
Ringservice.applySettings(id, videoManagerCallback.getNativeParams(camId).toMap(getResources().getConfiguration().orientation));
Ringservice.switchInput(id, uri);
}
});
......
......@@ -77,7 +77,7 @@ interface IDRingService {
/* IM */
void sendTextMessage(in String callID, in String message);
long sendAccountTextMessage(in String accountid, in String to, in String msg);
void sendProfile(in String callID);
void transfer(in String callID, in String to);
void attendedTransfer(in String transferID, in String targetID);
......
......@@ -90,8 +90,8 @@ public class VideoManagerCallback extends VideoCallback
int id = Integer.valueOf(camid);
DeviceParams p = native_params.get(id);
DRingService.VideoParams new_params = new DRingService.VideoParams(id, format, p.size.x, p.size.y, rate);
new_params.rot_width = width;
new_params.rot_height = height;
new_params.rotWidth = width;
new_params.rotHeight = height;
mService.setVideoRotation(new_params, p.infos);
params.put(camid, new_params);
}
......
......@@ -28,6 +28,7 @@ import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import cx.ring.R;
......@@ -35,7 +36,9 @@ import cx.ring.service.StringMap;
import ezvcard.Ezvcard;
import ezvcard.VCard;
import ezvcard.VCardVersion;
import ezvcard.io.text.VCardWriter;
import ezvcard.property.FormattedName;
import ezvcard.property.Uid;
public class VCardUtils {
public static final String TAG = VCardUtils.class.getSimpleName();
......@@ -79,6 +82,11 @@ public class VCardUtils {
saveToDisk(vcard, filename, path, context);
}
public static void savePeerProfileToDisk(VCard vcard, String filename, Context context) {
String path = peerProfilePath(context);
saveToDisk(vcard, filename, path, context);
}
public static void saveLocalProfileToDisk(String vcard, Context context) {
String path = localProfilePath(context);
File vcardPath = new File(path);
......@@ -88,6 +96,20 @@ public class VCardUtils {
} else {
filename = String.valueOf(System.currentTimeMillis()) + ".vcf";
}
saveToDisk(vcard, filename, path, context);
}
public static void saveLocalProfileToDisk(VCard vcard, Context context) {
String path = localProfilePath(context);
File vcardPath = new File(path);
String filename;
if (vcardPath.exists() && vcardPath.listFiles().length > 0) {
filename = vcardPath.listFiles()[0].getName();
} else {
filename = String.valueOf(System.currentTimeMillis()) + ".vcf";
}
saveToDisk(vcard, filename, path, context);
}
......@@ -119,6 +141,35 @@ public class VCardUtils {
}
}
/**
* Saves a vcard string to an internal new vcf file.
*
* @param vcard the VCard to save
* @param filename the filename of the vcf
* @param path the path of the vcf
* @param context the context used to open streams.
*/
private static void saveToDisk(VCard vcard, String filename, String path, Context context) {
if (vcard == null || TextUtils.isEmpty(filename) || context == null) {
return;
}
File peerProfilesFile = new File(path);
if (!peerProfilesFile.exists()) {
peerProfilesFile.mkdirs();
}
File file = new File(path + File.separator + filename);
try {
VCardWriter writer = new VCardWriter(file, VCardVersion.V2_1);
writer.getRawWriter().getFoldedLineWriter().setLineLength(null);
writer.getRawWriter().getFoldedLineWriter().setNewline("\n");
writer.write(vcard);
writer.close();
} catch (Exception e) {
Log.e(TAG, "Error while saving VCard to disk", e);
}
}
public static VCard loadPeerProfileFromDisk(@Nullable String filename, @Nullable Context context) {
String path = peerProfilePath(context) + File.separator + filename;
return loadFromDisk(path, context);
......@@ -127,6 +178,7 @@ public class VCardUtils {
public static VCard loadLocalProfileFromDisk(@Nullable Context context) {
VCard vcard = null;
String path = localProfilePath(context);
if (!TextUtils.isEmpty(path)) {
File vcardPath = new File(path);
if (vcardPath.exists()) {
File[] listvCard = vcardPath.listFiles();
......@@ -134,6 +186,7 @@ public class VCardUtils {
vcard = loadFromDisk(listvCard[0].toString(), context);
}
}
}
if (vcard == null) {
Log.d(TAG, "load default profile");
......@@ -163,8 +216,8 @@ public class VCardUtils {
Log.d(TAG, "vcardPath not exist " + vcardPath);
return null;
}
VCard vcard = Ezvcard.parse(vcardPath).first();
VCard vcard = Ezvcard.parse(vcardPath).first();
Log.d(TAG, "vcard in loadFromDisk " + Ezvcard.write(vcard).go());
return vcard;
} catch (IOException e) {
......@@ -173,6 +226,26 @@ public class VCardUtils {
}
}
@Nullable
public static String vcardToString(VCard vcard) {
StringWriter writer = new StringWriter();
VCardWriter vcwriter = new VCardWriter(writer, VCardVersion.V2_1);
vcwriter.getRawWriter().getFoldedLineWriter().setLineLength(null);
vcwriter.getRawWriter().getFoldedLineWriter().setNewline("\n");
String stringVCard;
try {
vcwriter.write(vcard);
stringVCard = writer.toString();
vcwriter.close();
writer.close();
} catch (Exception e) {
Log.e(TAG, "Error while converting VCard to String", e);
stringVCard = null;
}
return stringVCard;
}
private static String peerProfilePath(Context context) {
return context.getFilesDir().getAbsolutePath() + File.separator + "peer_profiles";
}
......@@ -184,7 +257,8 @@ public class VCardUtils {
private static VCard setupDefaultProfile(Context context) {
VCard vcard = new VCard();
vcard.setFormattedName(new FormattedName(context.getString(R.string.unknown)));
saveLocalProfileToDisk(Ezvcard.write(vcard).version(VCardVersion.V2_1).go(), context);
vcard.setUid(new Uid(String.valueOf(System.currentTimeMillis())));
saveLocalProfileToDisk(vcard, context);
return vcard;
}
}
......@@ -30,7 +30,6 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
......@@ -65,9 +64,7 @@ import cx.ring.model.account.Account;
import cx.ring.service.LocalService;
import cx.ring.utils.CropImageUtils;
import cx.ring.utils.VCardUtils;
import ezvcard.Ezvcard;
import ezvcard.VCard;
import ezvcard.VCardVersion;
import ezvcard.parameter.ImageType;
import ezvcard.property.FormattedName;
import ezvcard.property.Photo;
......@@ -258,11 +255,11 @@ public class MenuHeaderView extends FrameLayout {
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
Photo photo = new Photo(stream.toByteArray(), ImageType.PNG);
mVCardProfile.removeProperties(Photo.class);
mVCardProfile.removeProperties(RawProperty.class);
mVCardProfile.addPhoto(photo);
}
VCardUtils.saveLocalProfileToDisk(Ezvcard.write(mVCardProfile).version(VCardVersion.V2_1).go(), getContext());
mVCardProfile.removeProperties(RawProperty.class);
VCardUtils.saveLocalProfileToDisk(mVCardProfile, getContext());
updateUserView();
}
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment