Commit 1e40d571 authored by Rob Shannon's avatar Rob Shannon

removing pollyd\jpolly and fixing a file name issue

Change-Id: I87f94fc3b3ff2a1457c914c1325dcd8101efd317
parent 5e8cbcb7
#
# Copyright (C) 2011 The Android Open-Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/cm_evitareul.mk
......@@ -70,6 +70,7 @@ BOARD_USE_SKIA_LCDTEXT := true
BOARD_HAVE_BLUETOOTH := true
BOARD_HAVE_BLUETOOTH_BCM := true
BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR ?= device/htc/evitareul/bluetooth
BOARD_BLUEDROID_VENDOR_CONF := device/htc/evitareul/bluetooth/vnd_evitareul.txt
# USB
TARGET_USE_CUSTOM_LUN_FILE_PATH := "/sys/class/android_usb/f_mass_storage/lun0/file"
......
BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyHS2"
FW_PATCHFILE_LOCATION = "/system/etc/firmware/"
SCO_USE_I2S_INTERFACE = TRUE
SCO_I2SPCM_IF_ROLE = 0
BTVND_DBG = FALSE
BTHW_DBG = FALSE
VNDUSERIAL_DBG = FALSE
UPIO_DBG = FALSE
UART_TARGET_BAUD_RATE=4000000
This diff is collapsed.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Polly
LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ch.blinkenlights.android.polly"
android:versionCode="1"
android:versionName="1.0">
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:theme="@android:style/Theme.Dialog">
<activity android:name="CallState"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<service android:name=".PollyService" />
<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="false"
android:label="BootReceiver"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Polly volume observer</string>
</resources>
/*
* Copyright (C) 2012 Adrian Ulrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.blinkenlights.android.polly;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.v("Polly_BootReceiver", "Starting service");
context.startService(new Intent(context, PollyService.class));
}
}
/*
* Copyright (C) 2012 Adrian Ulrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.blinkenlights.android.polly;
import android.app.Activity;
import android.os.Bundle;
import android.content.Intent;
public class CallState extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(getApplicationContext(), PollyService.class));
finish();
}
}
/*
* Copyright (C) 2012 Adrian Ulrich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.blinkenlights.android.polly;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.TelephonyManager;
import android.media.AudioManager;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import java.lang.reflect.InvocationTargetException;
import java.lang.IllegalAccessException;
import java.lang.IllegalArgumentException;
import java.lang.ClassNotFoundException;
import java.lang.NoSuchMethodException;
import java.lang.reflect.Method;
import java.lang.Exception;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class PollyService extends Service {
private final IBinder ply_binder = new LocalBinder();
private final String rild_socket = "/dev/socket/rild-audio-gsm";
private final String INTENT_VOLUME = "android.media.VOLUME_CHANGED_ACTION"; /* sent if user changes any volume */
private final String INTENT_PHONESTATE = "android.intent.action.PHONE_STATE"; /* dialing, incall or hangup */
private final String INTENT_AIRPLANE = "android.intent.action.AIRPLANE_MODE"; /* switching from/to airplane mode */
private AudioManager aMgr;
private TelephonyManager tMgr;
private int lastvol = -1;
private boolean inCall = false;
private static String TAG = "PollyService";
private static boolean boothackDone = false;
@Override
public IBinder onBind(Intent i) {
return ply_binder;
}
public class LocalBinder extends Binder {
public PollyService getService() {
return PollyService.this;
}
}
@Override
public void onCreate() {
aMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
tMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// initial value
lastvol = aMgr.getStreamVolume(aMgr.STREAM_VOICE_CALL);
// maxwen: service can be restarted and will send headset insert then
// which will cause troubles with apps listening to it
//if(isAudioVolumeHackRequired()){
// applyAudioVolumeHack();
//}
registerReceiver(ply_receiver, new IntentFilter(INTENT_VOLUME)); /* undocumented */
registerReceiver(ply_receiver, new IntentFilter(INTENT_AIRPLANE));
registerReceiver(ply_receiver, new IntentFilter(INTENT_PHONESTATE));
}
private boolean isAudioVolumeHackRequired() {
if(!boothackDone){
String value = fileReadOneLine("/sys/class/switch/h2w/state");
return value!=null && value.equals("0");
}
return false;
}
private void applyAudioVolumeHack() {
Log.d(TAG, "apply volume hack");
try {
Class paramString = String.class;
Class paramInt = Integer.TYPE;
Class c = Class.forName(aMgr.getClass().getName());
Method f = c.getDeclaredMethod("setWiredDeviceConnectionState", paramInt, paramInt, paramString);
f.setAccessible(true);
f.invoke(aMgr, 8, 1, new String("Headset"));
f.invoke(aMgr, 8, 0, new String("Headset"));
f.setAccessible(false);
boothackDone = true;
Log.d(TAG,"apply volume hack success");
} catch (InvocationTargetException e) {
Log.d(TAG,"apply volume hack failed - exception " + e.getTargetException());
} catch (Exception e) {
Log.d(TAG,"apply volume hack - exception " + e);
}
}
private String fileReadOneLine(String fname) {
BufferedReader br;
String line = null;
try {
br = new BufferedReader(new FileReader(fname), 512);
try {
line = br.readLine();
} finally {
br.close();
}
} catch (Exception e) {
Log.e(TAG, "IO Exception when reading file " + fname + " " + e);
}
return line;
}
public void onDestroy() {
unregisterReceiver(ply_receiver);
}
private final BroadcastReceiver ply_receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
String ia = intent.getAction();
xlog("intent "+ia+" received");
if(ia == INTENT_VOLUME) { updateIncallVolume(); }
if(ia == INTENT_PHONESTATE) { checkPhoneState(); }
if(ia == INTENT_AIRPLANE) { checkAirplaneState(intent); }
}
/**************************************************************
** Fixup the volume on the modem - uses aMgr **
**************************************************************/
private void updateIncallVolume() {
/* android volumes go from 0-5
** but the modem expects 32-82
*/
int curvol = aMgr.getStreamVolume(aMgr.STREAM_VOICE_CALL);
if(lastvol != curvol) {
String vparam = "@volo,40,8,3,"+(32+curvol*10);
xlog("updating incall volume: "+vparam);
sendToPollySocket(vparam);
lastvol = curvol;
}
}
private void resetIncallVolume() {
String vparam = "@@";
xlog("reset incall volume: "+vparam);
sendToPollySocket(vparam);
}
/**************************************************************
** Force a volume-set if we switched to incall mode **
** This is racy, but it seems that we always get called **
** after libcallvolume.so finished the initial setup **
**************************************************************/
private void checkPhoneState() {
if(tMgr.getCallState() == tMgr.CALL_STATE_OFFHOOK) {
xlog("we are IN_CALL - forcing audio setting");
lastvol = -1;
updateIncallVolume();
inCall = true;
} else if(inCall && tMgr.getCallState() == tMgr.CALL_STATE_IDLE) {
xlog("we are END_CALL - reset audio setting");
resetIncallVolume();
inCall = false;
}
}
/**************************************************************
** Tell pollyd that it should exit/restart itself **
** This is needed to re-connect to gsmmux **
**************************************************************/
private void checkAirplaneState(Intent intent) {
boolean going_offline = intent.getExtras().getBoolean("state");
if(going_offline == false) {
xlog("exiting airplane state, restarting pollyd");
sendToPollySocket("kill,DEAD_PARROT"); // from pollyd.h kill, -> dummy space (volo,)
}
}
/**************************************************************
** Sends given string to pollyd **
**************************************************************/
private void sendToPollySocket(String whatever) {
LocalSocket lsock = new LocalSocket();
try {
lsock.connect(new LocalSocketAddress(rild_socket, LocalSocketAddress.Namespace.FILESYSTEM));
lsock.getOutputStream().write(whatever.getBytes());
}
catch (Exception e) {
xlog("sendToPollySocket "+e);
}
try {
lsock.close();
} catch(Exception e) {}
}
/**************************************************************
** Send given string to android log **
**************************************************************/
private void xlog(String msg) {
Log.d(TAG, msg);
}
};
}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := pollyd.c
LOCAL_CFLAGS := -Os
LOCAL_MODULE := pollyd
LOCAL_MODULE_TAGS := optional
LOCAL_SYSTEM_SHARED_LIBRARIES := libc liblog
include $(BUILD_EXECUTABLE)
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# If you don't need to do a full clean build but would like to touch
# a file or delete some intermediate files, add a clean step to the end
# of the list. These steps will only be run once, if they haven't been
# run before.
#
# E.g.:
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
#
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
# files that are missing or have been moved.
#
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
# Use $(OUT_DIR) to refer to the "out" directory.
#
# If you need to re-do something that's already mentioned, just copy
# the command and add it to the bottom of the list. E.g., if a change
# that you made last week required touching a file and a change you
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
/*
**
** (C) 2012 Adrian Ulrich
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
**
*/
#define LOG_TAG "pollyd"
#include <cutils/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "pollyd.h"
int main() {
ALOGD("startup");
int afd, pfd, cfd;
char rbuff[GBUFFSIZE];
size_t buff_len;
int atlen = strlen(AT_PREFIX);
gid_t jgid;
int setVolumeFromPolly = 0;
int pollyVolumeLevel = 0, volumeLevel;
char buf[GBUFFSIZE];
char* bufStart;
char* volumeStart;
char volumeBuf[2];
int cnt=0;
/* make socket unreadable */
umask( 0777 );
/* get unix domain socket and pts */
afd = get_audio_socket();
pfd = get_pts_socket();
jgid= get_jpolly_gid();
/* only allow write access to the radio user */
chown(SOCKET_PATH, USER_MEDIA, jgid);
chmod(SOCKET_PATH, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP );
/* drop root */
setgid(jgid);
setuid(USER_MEDIA);
if(setuid(0) != -1)
xdie("failed to drop root!");
/* terminates process if modem is stuck */
signal(SIGALRM, suicide);
ALOGD("socket setup finished. afd=%d, pfd=%d", afd, pfd);
while( (cfd = accept(afd, NULL, NULL)) ) {
/* read incomding data: we expect something like this:
path,40,5,3,0,0,1,3,0,1,0,1,2,13
..but we need..
AT+XDRV=40,5,3,0,0,1,3,0,1,0,1,2,13
the AT command string is 3 bytes longer, so we read to rbuff[3]
and overwrite the rest afterwards
*/
memset(&buf, 0, GBUFFSIZE);
cnt=read(cfd, &buf, GBUFFSIZE-3-2);
bufStart = buf;
// this message comes from Polly for setting volume
if(buf[0] == '@'){
if(buf[1] == '@'){
setVolumeFromPolly=0;
pollyVolumeLevel=0;
continue;
}
cnt--;
setVolumeFromPolly=1;
// remove leading @
bufStart++;
// get volume Polly sets
volumeStart=bufStart+strlen("volo,40,8,3,");
strncpy(volumeBuf, volumeStart, 2);
pollyVolumeLevel=atoi(volumeBuf);
ALOGD("Volume %d set from Polly", pollyVolumeLevel);
}
memset(&rbuff, 0, GBUFFSIZE);
memcpy(&rbuff[3], bufStart, cnt);
buff_len = 3+cnt;
memcpy(&rbuff, AT_PREFIX, atlen); /* add AT+XDRV= */
memcpy(&rbuff[buff_len], "\r\0", 2); /* terminate string */
/* send command to modem if it looks ok */
if(buff_len == TERM_LEN &&
memcmp(&rbuff, TERM_MAGIC, TERM_LEN) == 0) {
ALOGD("Poison cracker received, commiting suicide in %d seconds", TERM_DELAY);
sleep(TERM_DELAY);
xdie("terminating");
}
else if(buff_len >= CALLVOLUME_CMDLEN &&
at_args_sane(&rbuff[atlen], buff_len-atlen) == 1) {
if(!strncmp(rbuff, VOLUME_SET_CMD, strlen(VOLUME_SET_CMD))){
if(setVolumeFromPolly){
volumeStart=rbuff+strlen(VOLUME_SET_CMD);
strncpy(volumeBuf, volumeStart, 2);
volumeLevel = atoi(volumeBuf);
if (volumeLevel != pollyVolumeLevel) {
ALOGD("Ignoring volume %d that comes not from Polly", volumeLevel);
continue;
}
}
}
alarm(AT_TIMEOUT);
send_xdrv_command(rbuff, pfd);
alarm(0);
}
else {
ALOGD("silently dropping invalid command with %d bytes len", buff_len);
}
close(cfd);
}
ALOGD("exiting, accept returned false on fd %d", afd);
close(afd);
close(pfd);
xdie("terminating");
return 0;
}
/*
** Check if given string only contains 0-9 and ,
*/
int at_args_sane(char *buffer, size_t bufflen) {
size_t i;
int sane=1;
for(i=0; i<bufflen;i++) {
if(buffer[i] >= '0' && buffer[i] <= '9')
continue;
if(buffer[i] == ',')
continue;
sane = 0;
break;
}
return sane;
}
/*
** Creates the socket used by libcallvolume
*/
int get_audio_socket() {
struct sockaddr_un saddr;
int afd;
if( (afd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
xdie("Could not create new socket");
saddr.sun_family = AF_UNIX;
strcpy(saddr.sun_path, SOCKET_PATH);
unlink(SOCKET_PATH); // may fail
if( bind(afd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_un) ) != 0 )
xdie("bind failed");
if(listen(afd, 64))
xdie("listen failed!");
return afd;
}
/*
** Send an AT command to the modem
** Returns != 0 if the reply contained OK
*/
void send_xdrv_command(const char *cmd, int fd) {
char atbuff[GBUFFSIZE];
size_t bread;
struct timespec tx;
/* the modem needs some time -fixme: this is hacky */
tx.tv_sec = 0;
tx.tv_nsec = 75000000;
ALOGD(">>> %s", cmd);
if( write(fd, cmd, strlen(cmd)) == -1 )
xdie("mux error: write failed");
nanosleep(&tx, NULL);
bread = read(fd, &atbuff, GBUFFSIZE);
ALOGD("<<< %d bytes", bread);
/* fixme: this should probably search for \r\nOK\r\n */
}
/*
** Try to grab a new pty
** Returns an opened FD, dies on error
*/
int get_pts_socket() {