audio: rework bluetooth headset recognition

This commit is contained in:
Gautier Pelloux-Prayer 2016-01-06 17:17:57 +01:00
parent 6ed2bd5726
commit e06564105f
11 changed files with 572 additions and 450 deletions

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CallOutgoingView">
@ -12,6 +12,12 @@
<outlet property="landscapeView" destination="Czn-ec-dh8" id="ZIk-2g-9Qk"/>
<outlet property="nameLabel" destination="d5s-yP-8VE" id="0VY-HP-ovD"/>
<outlet property="portraitView" destination="25" id="26I-da-00C"/>
<outlet property="routesBluetoothButton" destination="SH1-xD-Agw" id="ifX-Dy-Tcb"/>
<outlet property="routesButton" destination="29K-Sd-aHF" id="MVM-Mb-OWE"/>
<outlet property="routesEarpieceButton" destination="zs4-Zy-FrP" id="TOt-D3-635"/>
<outlet property="routesSpeakerButton" destination="oKz-6p-EAF" id="yIx-qF-Gd7"/>
<outlet property="routesView" destination="iyf-nk-ORJ" id="LBJ-Rm-VUX"/>
<outlet property="speakerButton" destination="G7m-Av-QlR" id="UHW-L2-NDM"/>
<outlet property="view" destination="25" id="26"/>
</connections>
</placeholder>
@ -27,7 +33,6 @@
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="NFl-sb-0TV" userLabel="headerBar">
<rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="27"/>
<state key="normal" title="OUTGOING CALL" backgroundImage="color_F.png">
<color key="titleColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -37,7 +42,6 @@
<label opaque="NO" userInteractionEnabled="NO" tag="4" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="John Doe" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="19" id="d5s-yP-8VE" userLabel="nameLabel">
<rect key="frame" x="0.0" y="92" width="375" height="52"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="33"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
@ -45,7 +49,6 @@
<label opaque="NO" userInteractionEnabled="NO" tag="5" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="john.doe@sip.linphone.org" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" id="2fa-Ag-3GW" userLabel="addressLabel">
<rect key="frame" x="4" y="146" width="367" height="34"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -53,12 +56,84 @@
<imageView userInteractionEnabled="NO" tag="6" contentMode="scaleAspectFit" image="avatar.png" id="bNo-O5-DWh" userLabel="avatarImage" customClass="UIRoundedImageView">
<rect key="frame" x="87" y="214" width="200" height="200"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Contact avatar">
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
<bool key="isElement" value="YES"/>
</accessibility>
</imageView>
<view hidden="YES" tag="37" contentMode="scaleToFill" id="iyf-nk-ORJ" userLabel="routesView">
<rect key="frame" x="94" y="364" width="94" height="198"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" tag="38" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_F.png" id="xEp-Iw-uII" userLabel="backgroundColor">
<rect key="frame" x="0.0" y="0.0" width="94" height="198"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" tag="39" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="SH1-xD-Agw" userLabel="routesBluetoothButton" customClass="UIBluetoothButton">
<rect key="frame" x="0.0" y="0.0" width="94" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Bluetooth"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="titleEdgeInsets" minX="0.0" minY="28" maxX="0.0" maxY="0.0"/>
<state key="normal" image="route_bluetooth_default.png">
<color key="titleColor" red="0.25490196079999999" green="0.28235294119999998" blue="0.30980392159999998" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="route_bluetooth_disabled.png">
<color key="titleColor" red="0.65098039220000004" green="0.70196078429999997" blue="0.74901960779999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="selected" image="route_bluetooth_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png">
<color key="titleColor" red="0.81176470590000005" green="0.29803921570000003" blue="0.16078431369999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<connections>
<action selector="onRoutesBluetoothClick:" destination="-1" eventType="touchUpInside" id="0bq-3n-xii"/>
</connections>
</button>
<button opaque="NO" tag="40" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="zs4-Zy-FrP" userLabel="routesEarpieceButton">
<rect key="frame" x="0.0" y="66" width="94" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Receiver"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="titleEdgeInsets" minX="0.0" minY="28" maxX="0.0" maxY="0.0"/>
<state key="normal" image="route_earpiece_default.png">
<color key="titleColor" red="0.25490196079999999" green="0.28235294119999998" blue="0.30980392159999998" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="route_earpiece_disabled.png">
<color key="titleColor" red="0.65098039220000004" green="0.70196078429999997" blue="0.74901960779999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="selected" image="route_earpiece_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png">
<color key="titleColor" red="0.81176470590000005" green="0.29803921570000003" blue="0.16078431369999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<connections>
<action selector="onRoutesEarpieceClick:" destination="-1" eventType="touchUpInside" id="YRr-Kn-GgV"/>
</connections>
</button>
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="oKz-6p-EAF" userLabel="routesSpeakerButton" customClass="UISpeakerButton">
<rect key="frame" x="0.0" y="132" width="94" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" label="Speaker"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="titleEdgeInsets" minX="0.0" minY="28" maxX="0.0" maxY="0.0"/>
<state key="normal" image="route_speaker_default.png">
<color key="titleColor" red="0.25490196079999999" green="0.28235294119999998" blue="0.30980392159999998" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="route_speaker_disabled.png">
<color key="titleColor" red="0.65098039220000004" green="0.70196078429999997" blue="0.74901960779999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="selected" image="route_speaker_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png">
<color key="titleColor" red="0.81176470590000005" green="0.29803921570000003" blue="0.16078431369999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<connections>
<action selector="onRoutesSpeakerClick:" destination="-1" eventType="touchUpInside" id="g4L-6P-Iqw"/>
</connections>
</button>
</subviews>
</view>
<view tag="7" contentMode="scaleToFill" id="8Qi-Cq-3XH" userLabel="tabBar">
<rect key="frame" x="0.0" y="562" width="375" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
@ -66,12 +141,10 @@
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_F.png" id="vyh-Us-8kj" userLabel="backgroundColor">
<rect key="frame" x="0.0" y="0.0" width="375" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<animations/>
</imageView>
<button opaque="NO" tag="9" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="26e-Pj-2Oh" userLabel="microButton" customClass="UIMicroButton">
<rect key="frame" x="0.0" y="0.0" width="94" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Accept"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="micro_default.png">
@ -84,7 +157,6 @@
<button opaque="NO" tag="10" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="G7m-Av-QlR" userLabel="speakerButton" customClass="UISpeakerButton">
<rect key="frame" x="94" y="0.0" width="94" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Accept"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="speaker_default.png">
@ -94,10 +166,24 @@
<state key="selected" image="speaker_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png"/>
</button>
<button hidden="YES" opaque="NO" tag="54" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="29K-Sd-aHF" userLabel="routesButton" customClass="UIToggleButton">
<rect key="frame" x="94" y="0.0" width="94" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Route"/>
<inset key="titleEdgeInsets" minX="0.0" minY="38" maxX="0.0" maxY="0.0"/>
<state key="normal" image="routes_default.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="routes_disabled.png"/>
<state key="selected" image="routes_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png"/>
<connections>
<action selector="onRoutesClick:" destination="-1" eventType="touchUpInside" id="hXX-8a-7M4"/>
</connections>
</button>
<button opaque="NO" tag="11" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="AaM-cH-pvW" userLabel="declineButton">
<rect key="frame" x="187" y="0.0" width="188" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Decline"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="call_hangup_default.png" backgroundImage="color_D.png">
@ -110,15 +196,12 @@
</connections>
</button>
</subviews>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</subviews>
<animations/>
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina47"/>
<point key="canvasLocation" x="29.5" y="166.5"/>
@ -134,7 +217,6 @@
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="oAv-Cz-FaR" userLabel="headerBar">
<rect key="frame" x="0.0" y="0.0" width="667" height="66"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="27"/>
<state key="normal" title="OUTGOING CALL" backgroundImage="color_F.png">
<color key="titleColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@ -144,7 +226,6 @@
<label opaque="NO" userInteractionEnabled="NO" tag="4" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="19" id="ubQ-ZN-AhT" userLabel="nameLabel">
<rect key="frame" x="298" y="121" width="369" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="33"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
@ -152,7 +233,6 @@
<label opaque="NO" userInteractionEnabled="NO" tag="5" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="john.doe@sip.linphone.org" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" id="Fj8-Pu-ShI" userLabel="addressLabel">
<rect key="frame" x="298" y="166" width="368" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -160,12 +240,75 @@
<imageView userInteractionEnabled="NO" tag="6" contentMode="scaleAspectFit" image="avatar.png" id="1ZH-n6-QZ0" userLabel="avatarImage" customClass="UIRoundedImageView">
<rect key="frame" x="110" y="74" width="180" height="180"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Contact avatar">
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
<bool key="isElement" value="YES"/>
</accessibility>
</imageView>
<view hidden="YES" tag="37" contentMode="scaleToFill" id="EaW-SR-bqv" userLabel="routesView">
<rect key="frame" x="167" y="72" width="167" height="198"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" tag="38" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_F.png" id="Tvo-Jg-0h8" userLabel="backgroundColor">
<rect key="frame" x="0.0" y="0.0" width="167" height="198"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" tag="39" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="N7s-YH-dJQ" userLabel="routesBluetoothButton" customClass="UIBluetoothButton">
<rect key="frame" x="0.0" y="0.0" width="167" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Bluetooth"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="titleEdgeInsets" minX="0.0" minY="28" maxX="0.0" maxY="0.0"/>
<state key="normal" image="route_bluetooth_default.png">
<color key="titleColor" red="0.25490196079999999" green="0.28235294119999998" blue="0.30980392159999998" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="route_bluetooth_disabled.png">
<color key="titleColor" red="0.65098039220000004" green="0.70196078429999997" blue="0.74901960779999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="selected" image="route_bluetooth_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png">
<color key="titleColor" red="0.81176470590000005" green="0.29803921570000003" blue="0.16078431369999999" alpha="1" colorSpace="deviceRGB"/>
</state>
</button>
<button opaque="NO" tag="40" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="bg7-Cv-tyO" userLabel="routesEarpieceButton">
<rect key="frame" x="0.0" y="66" width="167" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Receiver"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="titleEdgeInsets" minX="0.0" minY="28" maxX="0.0" maxY="0.0"/>
<state key="normal" image="route_earpiece_default.png">
<color key="titleColor" red="0.25490196079999999" green="0.28235294119999998" blue="0.30980392159999998" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="route_earpiece_disabled.png">
<color key="titleColor" red="0.65098039220000004" green="0.70196078429999997" blue="0.74901960779999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="selected" image="route_earpiece_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png">
<color key="titleColor" red="0.81176470590000005" green="0.29803921570000003" blue="0.16078431369999999" alpha="1" colorSpace="deviceRGB"/>
</state>
</button>
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="yd8-ed-g8u" userLabel="routesSpeakerButton" customClass="UISpeakerButton">
<rect key="frame" x="0.0" y="132" width="167" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" label="Speaker"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<inset key="titleEdgeInsets" minX="0.0" minY="28" maxX="0.0" maxY="0.0"/>
<state key="normal" image="route_speaker_default.png">
<color key="titleColor" red="0.25490196079999999" green="0.28235294119999998" blue="0.30980392159999998" alpha="1" colorSpace="deviceRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="route_speaker_disabled.png">
<color key="titleColor" red="0.65098039220000004" green="0.70196078429999997" blue="0.74901960779999999" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="selected" image="route_speaker_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png">
<color key="titleColor" red="0.81176470590000005" green="0.29803921570000003" blue="0.16078431369999999" alpha="1" colorSpace="deviceRGB"/>
</state>
</button>
</subviews>
</view>
<view tag="7" contentMode="scaleToFill" id="vJ1-A8-eFV" userLabel="tabBar">
<rect key="frame" x="0.0" y="270" width="667" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
@ -173,12 +316,10 @@
<imageView userInteractionEnabled="NO" tag="8" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_F.png" id="eYb-yI-yVB" userLabel="backgroundColor">
<rect key="frame" x="0.0" y="0.0" width="667" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<animations/>
</imageView>
<button opaque="NO" tag="9" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jLg-1u-ulZ" userLabel="microButton" customClass="UIMicroButton">
<rect key="frame" x="0.0" y="0.0" width="167" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Accept"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="micro_default.png">
@ -191,7 +332,6 @@
<button opaque="NO" tag="10" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="5CY-aN-NLX" userLabel="speakerButton" customClass="UISpeakerButton">
<rect key="frame" x="167" y="0.0" width="167" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Accept"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="speaker_default.png">
@ -201,10 +341,21 @@
<state key="selected" image="speaker_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png"/>
</button>
<button hidden="YES" opaque="NO" tag="54" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="61B-DK-jZ6" userLabel="routesButton" customClass="UIToggleButton">
<rect key="frame" x="167" y="0.0" width="167" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<accessibility key="accessibilityConfiguration" label="Route"/>
<inset key="titleEdgeInsets" minX="0.0" minY="38" maxX="0.0" maxY="0.0"/>
<state key="normal" image="routes_default.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="disabled" image="routes_disabled.png"/>
<state key="selected" image="routes_selected.png"/>
<state key="highlighted" backgroundImage="color_E.png"/>
</button>
<button opaque="NO" tag="11" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jfG-HJ-FPI" userLabel="declineButton">
<rect key="frame" x="333" y="0.0" width="334" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<animations/>
<accessibility key="accessibilityConfiguration" label="Decline"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="call_hangup_default.png" backgroundImage="color_D.png">
@ -217,15 +368,12 @@
</connections>
</button>
</subviews>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</subviews>
<animations/>
<color key="backgroundColor" red="1" green="1" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina47"/>
@ -243,6 +391,18 @@
<image name="micro_default.png" width="29" height="37"/>
<image name="micro_disabled.png" width="29" height="37"/>
<image name="micro_selected.png" width="29" height="37"/>
<image name="route_bluetooth_default.png" width="16" height="25"/>
<image name="route_bluetooth_disabled.png" width="16" height="25"/>
<image name="route_bluetooth_selected.png" width="16" height="25"/>
<image name="route_earpiece_default.png" width="23" height="24"/>
<image name="route_earpiece_disabled.png" width="23" height="24"/>
<image name="route_earpiece_selected.png" width="23" height="24"/>
<image name="route_speaker_default.png" width="27" height="25"/>
<image name="route_speaker_disabled.png" width="27" height="25"/>
<image name="route_speaker_selected.png" width="27" height="25"/>
<image name="routes_default.png" width="37" height="25"/>
<image name="routes_disabled.png" width="37" height="25"/>
<image name="routes_selected.png" width="37" height="25"/>
<image name="speaker_default.png" width="27" height="25"/>
<image name="speaker_disabled.png" width="27" height="25"/>
<image name="speaker_selected.png" width="27" height="25"/>

View file

@ -386,7 +386,7 @@
<rect key="frame" x="0.0" y="0.0" width="94" height="198"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" tag="39" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="6uv-FV-mUL" userLabel="routesBluetoothButton">
<button opaque="NO" tag="39" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="6uv-FV-mUL" userLabel="routesBluetoothButton" customClass="UIBluetoothButton">
<rect key="frame" x="0.0" y="0.0" width="94" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Bluetooth"/>
@ -428,7 +428,7 @@
<action selector="onRoutesEarpieceClick:" destination="-1" eventType="touchUpInside" id="RqY-KM-K7M"/>
</connections>
</button>
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="go9-SC-yzb" userLabel="routesSpeakerButton">
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="go9-SC-yzb" userLabel="routesSpeakerButton" customClass="UISpeakerButton">
<rect key="frame" x="0.0" y="132" width="94" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" label="Speaker"/>
@ -979,7 +979,7 @@
<rect key="frame" x="0.0" y="0.0" width="84" height="198"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" tag="39" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="uPj-2J-1oA" userLabel="routesBluetoothButton">
<button opaque="NO" tag="39" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="uPj-2J-1oA" userLabel="routesBluetoothButton" customClass="UIBluetoothButton">
<rect key="frame" x="0.0" y="0.0" width="84" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Bluetooth"/>
@ -1021,7 +1021,7 @@
<action selector="onRoutesEarpieceClick:" destination="-1" eventType="touchUpInside" id="SlB-O8-JVa"/>
</connections>
</button>
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="dsJ-hG-m4c" userLabel="routesSpeakerButton">
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="dsJ-hG-m4c" userLabel="routesSpeakerButton" customClass="UISpeakerButton">
<rect key="frame" x="0.0" y="132" width="84" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" label="Speaker"/>
@ -1155,7 +1155,9 @@
<button hidden="YES" opaque="NO" tag="54" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="mxV-GD-O3N" userLabel="routesButton" customClass="UIToggleButton">
<rect key="frame" x="166" y="0.0" width="84" height="63"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Route"/>
<accessibility key="accessibilityConfiguration" label="Route">
<bool key="isElement" value="YES"/>
</accessibility>
<inset key="titleEdgeInsets" minX="0.0" minY="38" maxX="0.0" maxY="0.0"/>
<state key="normal" image="routes_default.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>

View file

@ -428,7 +428,7 @@
<action selector="onRoutesEarpieceClick:" destination="-1" eventType="touchUpInside" id="RqY-KM-K7M"/>
</connections>
</button>
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="go9-SC-yzb" userLabel="routesSpeakerButton">
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="go9-SC-yzb" userLabel="routesSpeakerButton" customClass="UISpeakerButton">
<rect key="frame" x="0.0" y="132" width="100" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" label="Speaker"/>
@ -1021,7 +1021,7 @@
<action selector="onRoutesEarpieceClick:" destination="-1" eventType="touchUpInside" id="SlB-O8-JVa"/>
</connections>
</button>
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="dsJ-hG-m4c" userLabel="routesSpeakerButton">
<button opaque="NO" tag="41" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="dsJ-hG-m4c" userLabel="routesSpeakerButton" customClass="UISpeakerButton">
<rect key="frame" x="0.0" y="132" width="100" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<accessibility key="accessibilityConfiguration" label="Speaker"/>

View file

@ -28,7 +28,13 @@
}
@property(weak, nonatomic) IBOutlet UIRoundedImageView *avatarImage;
@property(weak, nonatomic) IBOutlet UILabel *nameLabel;
@property(weak, nonatomic) IBOutlet UISpeakerButton *speakerButton;
@property(weak, nonatomic) IBOutlet UILabel *addressLabel;
@property(weak, nonatomic) IBOutlet UIToggleButton *routesButton;
@property(weak, nonatomic) IBOutlet UIView *routesView;
@property(weak, nonatomic) IBOutlet UIBluetoothButton *routesBluetoothButton;
@property(weak, nonatomic) IBOutlet UIButton *routesEarpieceButton;
@property(weak, nonatomic) IBOutlet UISpeakerButton *routesSpeakerButton;
- (IBAction)onDeclineClick:(id)sender;

View file

@ -48,6 +48,11 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(bluetoothAvailabilityUpdateEvent:)
name:kLinphoneBluetoothAvailabilityUpdate
object:nil];
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
if (!call) {
if (![PhoneMainView.instance popCurrentView]) {
@ -61,6 +66,37 @@ static UICompositeViewDescription *compositeDescription = nil;
ms_free(uri);
[_avatarImage setImage:[FastAddressBook imageForAddress:addr thumbnail:NO] bordered:YES withRoundedRadius:YES];
}
[self hideSpeaker:LinphoneManager.instance.bluetoothAvailable];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (IBAction)onRoutesBluetoothClick:(id)sender {
[self hideRoutes:TRUE animated:TRUE];
[[LinphoneManager instance] setBluetoothEnabled:TRUE];
}
- (IBAction)onRoutesEarpieceClick:(id)sender {
[self hideRoutes:TRUE animated:TRUE];
[[LinphoneManager instance] setSpeakerEnabled:FALSE];
[[LinphoneManager instance] setBluetoothEnabled:FALSE];
}
- (IBAction)onRoutesSpeakerClick:(id)sender {
[self hideRoutes:TRUE animated:TRUE];
[[LinphoneManager instance] setSpeakerEnabled:TRUE];
}
- (IBAction)onRoutesClick:(id)sender {
if ([_routesView isHidden]) {
[self hideRoutes:FALSE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
} else {
[self hideRoutes:TRUE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
}
}
- (IBAction)onDeclineClick:(id)sender {
@ -68,6 +104,46 @@ static UICompositeViewDescription *compositeDescription = nil;
if (call) {
linphone_core_terminate_call([LinphoneManager getLc], call);
}
[PhoneMainView.instance popCurrentView];
if (![PhoneMainView.instance popCurrentView]) {
[PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription];
}
}
- (void)hideRoutes:(BOOL)hidden animated:(BOOL)animated {
if (IPAD)
return;
if (hidden) {
[_routesButton setOff];
} else {
[_routesButton setOn];
}
_routesBluetoothButton.selected = LinphoneManager.instance.bluetoothEnabled;
_routesSpeakerButton.selected = LinphoneManager.instance.speakerEnabled;
_routesEarpieceButton.selected = !_routesBluetoothButton.selected && !_routesSpeakerButton.selected;
if (hidden != _routesView.hidden) {
// if (animated) {
// [self hideAnimation:hidden forView:_routesView completion:nil];
// } else {
[_routesView setHidden:hidden];
// }
}
}
- (void)hideSpeaker:(BOOL)hidden {
if (IPAD)
return;
_speakerButton.hidden = hidden;
_routesButton.hidden = !hidden;
}
#pragma mark - Event Functions
- (void)bluetoothAvailabilityUpdateEvent:(NSNotification *)notif {
bool available = [[notif.userInfo objectForKey:@"available"] intValue];
[self hideSpeaker:available];
}
@end

View file

@ -73,104 +73,6 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark - ViewController Functions
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
UIDevice *device = [UIDevice currentDevice];
device.proximityMonitoringEnabled = YES;
[PhoneMainView.instance setVolumeHidden:TRUE];
hiddenVolume = TRUE;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self disableVideoDisplay:NO];
if (hideControlsTimer != nil) {
[hideControlsTimer invalidate];
hideControlsTimer = nil;
}
if (hiddenVolume) {
[PhoneMainView.instance setVolumeHidden:FALSE];
hiddenVolume = FALSE;
}
if (videoDismissTimer) {
[self dismissVideoActionSheet:videoDismissTimer];
[videoDismissTimer invalidate];
videoDismissTimer = nil;
}
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:kLinphoneCallUpdate object:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(messageReceived:)
name:kLinphoneMessageReceived
object:nil];
[self updateUnreadMessage:FALSE];
// Update on show
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
LinphoneCallState state = (call != NULL) ? linphone_call_get_state(call) : 0;
[self callUpdate:call state:state animated:FALSE];
[self hideRoutes:FALSE];
[self hideOptions:FALSE];
[self hidePad:FALSE];
[self showSpeaker];
[self callDurationUpdate];
[self onCurrentCallChange];
// Set windows (warn memory leaks)
linphone_core_set_native_video_window_id([LinphoneManager getLc], (__bridge void *)(_videoView));
linphone_core_set_native_preview_window_id([LinphoneManager getLc], (__bridge void *)(_videoPreview));
// Enable tap
[singleFingerTap setEnabled:TRUE];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdateEvent:)
name:kLinphoneCallUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(bluetoothAvailabilityUpdateEvent:)
name:kLinphoneBluetoothAvailabilityUpdate
object:nil];
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(callDurationUpdate)
userInfo:nil
repeats:YES];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIApplication sharedApplication] setIdleTimerDisabled:false];
UIDevice *device = [UIDevice currentDevice];
device.proximityMonitoringEnabled = NO;
[PhoneMainView.instance fullScreen:false];
// Disable tap
[singleFingerTap setEnabled:FALSE];
if (linphone_core_get_calls_nb([LinphoneManager getLc]) == 0) {
// reseting speaker button because no more call
_speakerButton.selected = FALSE;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
@ -218,17 +120,120 @@ static UICompositeViewDescription *compositeDescription = nil;
[PhoneMainView.instance.view removeGestureRecognizer:singleFingerTap];
// Remove all observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self updateUnreadMessage:FALSE];
// Update on show
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
LinphoneCallState state = (call != NULL) ? linphone_call_get_state(call) : 0;
[self callUpdate:call state:state animated:FALSE];
[self hideRoutes:TRUE animated:FALSE];
[self hideOptions:TRUE animated:FALSE];
[self hidePad:TRUE animated:FALSE];
[self hideSpeaker:LinphoneManager.instance.bluetoothAvailable];
[self callDurationUpdate];
[self onCurrentCallChange];
// Set windows (warn memory leaks)
linphone_core_set_native_video_window_id([LinphoneManager getLc], (__bridge void *)(_videoView));
linphone_core_set_native_preview_window_id([LinphoneManager getLc], (__bridge void *)(_videoPreview));
// Enable tap
[singleFingerTap setEnabled:TRUE];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(messageReceived:)
name:kLinphoneMessageReceived
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(bluetoothAvailabilityUpdateEvent:)
name:kLinphoneBluetoothAvailabilityUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(callUpdateEvent:)
name:kLinphoneCallUpdate
object:nil];
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(callDurationUpdate)
userInfo:nil
repeats:YES];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
UIDevice.currentDevice.proximityMonitoringEnabled = YES;
[PhoneMainView.instance setVolumeHidden:TRUE];
hiddenVolume = TRUE;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self disableVideoDisplay:TRUE animated:NO];
if (hideControlsTimer != nil) {
[hideControlsTimer invalidate];
hideControlsTimer = nil;
}
if (hiddenVolume) {
[PhoneMainView.instance setVolumeHidden:FALSE];
hiddenVolume = FALSE;
}
if (videoDismissTimer) {
[self dismissVideoActionSheet:videoDismissTimer];
[videoDismissTimer invalidate];
videoDismissTimer = nil;
}
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[UIApplication sharedApplication] setIdleTimerDisabled:false];
UIDevice.currentDevice.proximityMonitoringEnabled = NO;
[PhoneMainView.instance fullScreen:false];
// Disable tap
[singleFingerTap setEnabled:FALSE];
if (linphone_core_get_calls_nb([LinphoneManager getLc]) == 0) {
// reseting speaker button because no more call
_speakerButton.selected = FALSE;
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
[self updateUnreadMessage:NO];
[self previewTouchLift];
[self showStatusBar:!videoShown || (_nameLabel.alpha > 0.f)];
[self hideStatusBar:videoShown && (_nameLabel.alpha == 0.f)];
}
#pragma mark -
#pragma mark - UI modification
- (void)hideSpinnerIndicator:(LinphoneCall *)call {
_videoWaitingForFirstImage.hidden = TRUE;
}
static void hideSpinner(LinphoneCall *call, void *user_data) {
CallView *thiz = (__bridge CallView *)user_data;
[thiz hideSpinnerIndicator:call];
}
- (void)updateBottomBar:(LinphoneCall *)call state:(LinphoneCallState)state {
LinphoneCore *lc = [LinphoneManager getLc];
@ -273,32 +278,27 @@ static UICompositeViewDescription *compositeDescription = nil;
case LinphoneCallError:
case LinphoneCallIncoming:
case LinphoneCallOutgoing:
[self hidePad:TRUE];
[self hideOptions:TRUE];
[self hideRoutes:TRUE];
[self hidePad:TRUE animated:TRUE];
[self hideOptions:TRUE animated:TRUE];
[self hideRoutes:TRUE animated:TRUE];
default:
break;
}
}
- (void)bluetoothAvailabilityUpdate:(bool)available {
if (available) {
[self hideSpeaker];
} else {
[self showSpeaker];
}
}
- (void)toggleControls:(id)sender {
bool controlsHidden = (_bottomBar.alpha == 0.0);
if (controlsHidden) {
[self showControls:sender];
} else {
[self hideControls:sender];
}
[self hideControls:!controlsHidden sender:sender];
}
- (void)showControls:(id)sender {
- (void)timerHideControls:(id)sender {
[self hideControls:TRUE sender:sender];
}
- (void)hideControls:(BOOL)hidden sender:(id)sender {
if (hidden == videoShown)
return;
if (hideControlsTimer) {
[hideControlsTimer invalidate];
hideControlsTimer = nil;
@ -308,153 +308,94 @@ static UICompositeViewDescription *compositeDescription = nil;
// show controls
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.35];
_pausedCallsTable.tableView.alpha = _videoCameraSwitch.alpha = _callPauseButton.alpha = 1.0;
_routesView.alpha = _optionsView.alpha = _numpadView.alpha = _bottomBar.alpha = 1.0;
_nameLabel.alpha = _durationLabel.alpha = .8;
_pausedCallsTable.tableView.alpha = _videoCameraSwitch.alpha = _callPauseButton.alpha = (hidden ? 0 : 1);
_routesView.alpha = _optionsView.alpha = _numpadView.alpha = _bottomBar.alpha = (hidden ? 1 : 0);
_nameLabel.alpha = _durationLabel.alpha = (hidden ? 0 : .8);
[self showStatusBar:true];
[self hideStatusBar:hidden];
[UIView commitAnimations];
[PhoneMainView.instance showTabBar:true];
[PhoneMainView.instance showTabBar:!hidden];
if (!hidden) {
// hide controls in 5 sec
hideControlsTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(hideControls:)
selector:@selector(timerHideControls:)
userInfo:nil
repeats:NO];
}
}
}
- (void)hideControls:(id)sender {
if (!videoShown)
- (void)disableVideoDisplay:(BOOL)disabled animated:(BOOL)animation {
if (disabled == videoShown && animation)
return;
if (hideControlsTimer) {
[hideControlsTimer invalidate];
hideControlsTimer = nil;
if (!disabled) {
[videoZoomHandler resetZoom];
}
if ([[PhoneMainView.instance currentView] equal:CallView.compositeViewDescription]) {
[PhoneMainView.instance showTabBar:false];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
_pausedCallsTable.tableView.alpha = _videoCameraSwitch.alpha = _nameLabel.alpha = _durationLabel.alpha =
_callPauseButton.alpha = 0.0;
_routesView.alpha = _optionsView.alpha = _numpadView.alpha = _bottomBar.alpha = 0.0;
[self showStatusBar:false];
[UIView commitAnimations];
}
}
- (void)enableVideoDisplay:(BOOL)animation {
if (videoShown && animation)
return;
videoShown = true;
[videoZoomHandler resetZoom];
if (animation) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
}
[_videoGroup setAlpha:1.0];
[_videoGroup setAlpha:disabled ? 0 : 1];
[self hideControls:nil];
[self hideControls:!disabled sender:nil];
if (animation) {
[UIView commitAnimations];
}
_videoPreview.hidden = (!linphone_core_self_view_enabled([LinphoneManager getLc]));
if ([LinphoneManager instance].frontCamId != nil) {
// only show camera switch button if we have more than 1 camera
[_videoCameraSwitch setHidden:FALSE];
}
[PhoneMainView.instance fullScreen:true];
[PhoneMainView.instance showTabBar:false];
#ifdef TEST_VIDEO_VIEW_CHANGE
[NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(_debugChangeVideoView)
userInfo:nil
repeats:YES];
#endif
// [self batteryLevelChanged:nil];
[_videoWaitingForFirstImage setHidden:NO];
[_videoWaitingForFirstImage startAnimating];
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
// linphone_call_params_get_used_video_codec return 0 if no video stream enabled
if (call != NULL && linphone_call_params_get_used_video_codec(linphone_call_get_current_params(call))) {
linphone_call_set_next_video_frame_decoded_callback(call, hideSpinner, (__bridge void *)(self));
}
}
- (void)disableVideoDisplay:(BOOL)animation {
if (!videoShown && animation)
return;
videoShown = false;
if (animation) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
}
[_videoGroup setAlpha:0.0];
[PhoneMainView.instance showTabBar:true];
[self showControls:nil];
[_videoCameraSwitch setHidden:TRUE];
if (animation) {
[UIView commitAnimations];
}
// only show camera switch button if we have more than 1 camera
_videoCameraSwitch.hidden = !disabled && ([LinphoneManager instance].frontCamId != nil);
_videoPreview.hidden = (!disabled && !linphone_core_self_view_enabled([LinphoneManager getLc]));
if (hideControlsTimer != nil) {
[hideControlsTimer invalidate];
hideControlsTimer = nil;
}
[PhoneMainView.instance fullScreen:false];
[PhoneMainView.instance fullScreen:!disabled];
[PhoneMainView.instance showTabBar:disabled];
if (!disabled) {
#ifdef TEST_VIDEO_VIEW_CHANGE
[NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(_debugChangeVideoView)
userInfo:nil
repeats:YES];
#endif
// [self batteryLevelChanged:nil];
[_videoWaitingForFirstImage setHidden:NO];
[_videoWaitingForFirstImage startAnimating];
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
// linphone_call_params_get_used_video_codec return 0 if no video stream enabled
if (call != NULL && linphone_call_params_get_used_video_codec(linphone_call_get_current_params(call))) {
linphone_call_set_next_video_frame_decoded_callback(call, hideSpinner, (__bridge void *)(self));
}
}
}
- (void)displayVideoCall:(BOOL)animated {
[self enableVideoDisplay:animated];
[self disableVideoDisplay:FALSE animated:animated];
}
- (void)displayTableCall:(BOOL)animated {
[self disableVideoDisplay:animated];
[self disableVideoDisplay:TRUE animated:animated];
}
- (void)showStatusBar:(BOOL)show {
- (void)hideStatusBar:(BOOL)hide {
/* we cannot use [PhoneMainView.instance show]; because it will automatically
resize current view to fill empty space, which will resize video. This is
indesirable since we do not want to crop/rescale video view */
PhoneMainView.instance.mainViewController.statusBarView.hidden = !show;
PhoneMainView.instance.mainViewController.statusBarView.hidden = hide;
}
#pragma mark - Spinner Functions
- (void)hideSpinnerIndicator:(LinphoneCall *)call {
_videoWaitingForFirstImage.hidden = TRUE;
}
static void hideSpinner(LinphoneCall *call, void *user_data) {
CallView *thiz = (__bridge CallView *)user_data;
[thiz hideSpinnerIndicator:call];
}
#pragma mark - UI modification
- (void)callDurationUpdate {
int duration = linphone_core_get_current_call([LinphoneManager getLc])
@ -484,111 +425,71 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
}
}
- (void)showPad:(BOOL)animated {
[_numpadButton setOn];
if ([_numpadView isHidden]) {
- (void)hidePad:(BOOL)hidden animated:(BOOL)animated {
if (hidden) {
[_numpadButton setOff];
} else {
[_numpadButton setOn];
}
if (hidden != _numpadView.hidden) {
if (animated) {
[self showAnimation:_numpadView
completion:^(BOOL finished){
}];
[self hideAnimation:hidden forView:_numpadView completion:nil];
} else {
[_numpadView setHidden:FALSE];
[_numpadView setHidden:hidden];
}
}
}
- (void)hidePad:(BOOL)animated {
[_numpadButton setOff];
if (![_numpadView isHidden]) {
if (animated) {
[self hideAnimation:_numpadView
completion:^(BOOL finished){
}];
} else {
[_numpadView setHidden:TRUE];
}
}
}
- (void)hideRoutes:(BOOL)hidden animated:(BOOL)animated {
if (IPAD)
return;
- (void)showRoutes:(BOOL)animated {
if (![LinphoneManager runningOnIpad]) {
[_routesButton setOn];
[_routesBluetoothButton setSelected:[[LinphoneManager instance] bluetoothEnabled]];
[_routesSpeakerButton setSelected:[[LinphoneManager instance] speakerEnabled]];
[_routesEarpieceButton setSelected:!([[LinphoneManager instance] bluetoothEnabled] ||
[[LinphoneManager instance] speakerEnabled])];
if ([_routesView isHidden]) {
if (animated) {
[self showAnimation:_routesView
completion:^(BOOL finished){
}];
} else {
[_routesView setHidden:FALSE];
}
}
}
}
- (void)hideRoutes:(BOOL)animated {
if (![LinphoneManager runningOnIpad]) {
if (hidden) {
[_routesButton setOff];
if (![_routesView isHidden]) {
if (animated) {
[self hideAnimation:_routesView
completion:^(BOOL finished){
}];
} else {
[_routesView setHidden:TRUE];
}
}
} else {
[_routesButton setOn];
}
}
- (void)showOptions:(BOOL)animated {
[_optionsButton setOn];
if ([_optionsView isHidden]) {
_routesBluetoothButton.selected = LinphoneManager.instance.bluetoothEnabled;
_routesSpeakerButton.selected = LinphoneManager.instance.speakerEnabled;
_routesEarpieceButton.selected = !_routesBluetoothButton.selected && !_routesSpeakerButton.selected;
if (hidden != _routesView.hidden) {
if (animated) {
[self showAnimation:_optionsView
completion:^(BOOL finished){
}];
[self hideAnimation:hidden forView:_routesView completion:nil];
} else {
[_optionsView setHidden:FALSE];
[_routesView setHidden:hidden];
}
}
}
- (void)hideOptions:(BOOL)animated {
[_optionsButton setOff];
if (![_optionsView isHidden]) {
- (void)hideOptions:(BOOL)hidden animated:(BOOL)animated {
if (hidden) {
[_optionsButton setOff];
} else {
[_optionsButton setOn];
}
if (hidden != _optionsView.hidden) {
if (animated) {
[self hideAnimation:_optionsView
completion:^(BOOL finished){
}];
[self hideAnimation:hidden forView:_optionsView completion:nil];
} else {
[_optionsView setHidden:TRUE];
[_optionsView setHidden:hidden];
}
}
}
- (void)showSpeaker {
if (![LinphoneManager runningOnIpad]) {
[_speakerButton setHidden:FALSE];
[_routesButton setHidden:TRUE];
}
}
- (void)hideSpeaker {
if (![LinphoneManager runningOnIpad]) {
[_speakerButton setHidden:TRUE];
[_routesButton setHidden:FALSE];
}
- (void)hideSpeaker:(BOOL)hidden {
if (IPAD)
return;
_speakerButton.hidden = hidden;
_routesButton.hidden = !hidden;
}
#pragma mark - Event Functions
- (void)bluetoothAvailabilityUpdateEvent:(NSNotification *)notif {
bool available = [[notif.userInfo objectForKey:@"available"] intValue];
[self bluetoothAvailabilityUpdate:available];
[self hideSpeaker:available];
}
- (void)callUpdateEvent:(NSNotification *)notif {
@ -774,9 +675,9 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
- (IBAction)onNumpadClick:(id)sender {
if ([_numpadView isHidden]) {
[self showPad:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
[self hidePad:FALSE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
} else {
[self hidePad:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
[self hidePad:TRUE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
}
}
@ -786,31 +687,31 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
}
- (IBAction)onRoutesBluetoothClick:(id)sender {
[self hideRoutes:TRUE];
[self hideRoutes:TRUE animated:TRUE];
[[LinphoneManager instance] setBluetoothEnabled:TRUE];
}
- (IBAction)onRoutesEarpieceClick:(id)sender {
[self hideRoutes:TRUE];
[self hideRoutes:TRUE animated:TRUE];
[[LinphoneManager instance] setSpeakerEnabled:FALSE];
[[LinphoneManager instance] setBluetoothEnabled:FALSE];
}
- (IBAction)onRoutesSpeakerClick:(id)sender {
[self hideRoutes:TRUE];
[self hideRoutes:TRUE animated:TRUE];
[[LinphoneManager instance] setSpeakerEnabled:TRUE];
}
- (IBAction)onRoutesClick:(id)sender {
if ([_routesView isHidden]) {
[self showRoutes:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
[self hideRoutes:FALSE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
} else {
[self hideRoutes:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
[self hideRoutes:TRUE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
}
}
- (IBAction)onOptionsTransferClick:(id)sender {
[self hideOptions:TRUE];
[self hideOptions:TRUE animated:TRUE];
// Go to dialer view
DialerView *view = VIEW(DialerView);
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
@ -821,7 +722,7 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
}
- (IBAction)onOptionsAddClick:(id)sender {
[self hideOptions:TRUE];
[self hideOptions:TRUE animated:TRUE];
// Go to dialer view
DialerView *view = VIEW(DialerView);
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
@ -831,9 +732,9 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
- (IBAction)onOptionsClick:(id)sender {
if ([_optionsView isHidden]) {
[self showOptions:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
[self hideOptions:FALSE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
} else {
[self hideOptions:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
[self hideOptions:TRUE animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]];
}
}
@ -843,27 +744,8 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
#pragma mark - Animation
- (void)showAnimation:(UIView *)target completion:(void (^)(BOOL finished))completion {
CGRect frame = target.frame;
int original_y = frame.origin.y;
frame.origin.y = self.view.frame.size.height;
target.frame = frame;
frame.origin.y = original_y;
target.hidden = NO;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
target.frame = frame;
}
completion:^(BOOL finished) {
target.frame = frame; // in case application did not finish
completion(finished);
}];
}
- (void)hideAnimation:(UIView *)target completion:(void (^)(BOOL finished))completion {
- (void)hideAnimation:(BOOL)hidden forView:(UIView *)target completion:(void (^)(BOOL finished))completion {
if (hidden) {
int original_y = target.frame.origin.y;
CGRect newFrame = target.frame;
newFrame.origin.y = self.view.frame.size.height;
@ -878,8 +760,29 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
originFrame.origin.y = original_y;
target.hidden = YES;
target.frame = originFrame;
completion(finished);
if (completion)
completion(finished);
}];
} else {
CGRect frame = target.frame;
int original_y = frame.origin.y;
frame.origin.y = self.view.frame.size.height;
target.frame = frame;
frame.origin.y = original_y;
target.hidden = NO;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
target.frame = frame;
}
completion:^(BOOL finished) {
target.frame = frame; // in case application did not finish
if (completion)
completion(finished);
}];
}
}
#pragma mark - Bounce

View file

@ -47,11 +47,6 @@
#define LINPHONE_LOGS_MAX_ENTRY 5000
static void audioRouteChangeListenerCallback(void *inUserData, // 1
AudioSessionPropertyID inPropertyID, // 2
UInt32 inPropertyValueSize, // 3
const void *inPropertyValue // 4
);
static LinphoneCore *theLinphoneCore = nil;
static LinphoneManager *theLinphoneManager = nil;
@ -256,11 +251,10 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
- (id)init {
if ((self = [super init])) {
AudioSessionInitialize(NULL, NULL, NULL, NULL);
OSStatus lStatus = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback, (__bridge void *)(self));
if (lStatus) {
LOGE(@"cannot register route change handler [%ld]", lStatus);
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(audioRouteChangeListenerCallback2:)
name:AVAudioSessionRouteChangeNotification
object:nil];
NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"];
self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil];
@ -298,15 +292,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
}
- (void)dealloc {
OSStatus lStatus = AudioSessionRemovePropertyListenerWithUserData(
kAudioSessionProperty_AudioRouteChange, audioRouteChangeListenerCallback, (__bridge void *)(self));
if (lStatus) {
LOGE(@"cannot un register route change handler [%ld]", lStatus);
}
[[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:kLinphoneGlobalStateUpdate];
[[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:kLinphoneConfiguringStateUpdate];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)silentPushFailed:(NSTimer *)timer {
@ -713,7 +699,9 @@ static void linphone_iphone_display_status(struct _LinphoneCore *lc, const char
if (linphone_core_get_calls_nb(theLinphoneCore) == 0) {
[self setSpeakerEnabled:FALSE];
[self removeCTCallCenterCb];
bluetoothAvailable = FALSE;
// disable this because I don't find anygood reason for it: bluetoothAvailable = FALSE;
// furthermore it introduces a bug when calling multiple times since route may not be
// reconfigured between cause leading to bluetooth being disabled while it should not
bluetoothEnabled = FALSE;
/*IOS specific*/
linphone_core_start_dtmf_stream(theLinphoneCore);
@ -1800,69 +1788,76 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
OSStatus lStatus = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &lNewRouteSize, &lNewRoute);
if (!lStatus && lNewRouteSize > 0) {
NSString *route = (__bridge NSString *)lNewRoute;
notallow = [route isEqualToString:@"Headset"] || [route isEqualToString:@"Headphone"] ||
[route isEqualToString:@"HeadphonesAndMicrophone"] || [route isEqualToString:@"HeadsetInOut"] ||
[route isEqualToString:@"Lineout"] || IPAD;
notallow = [route containsString:@"Heads"] || [route isEqualToString:@"Lineout"] || IPAD;
CFRelease(lNewRoute);
}
return !notallow;
}
static void audioRouteChangeListenerCallback(void *inUserData, // 1
AudioSessionPropertyID inPropertyID, // 2
UInt32 inPropertyValueSize, // 3
const void *inPropertyValue // 4
) {
if (inPropertyID != kAudioSessionProperty_AudioRouteChange)
return; // 5
LinphoneManager *lm = (__bridge LinphoneManager *)inUserData;
- (void)audioRouteChangeListenerCallback2:(NSNotification *)notif {
// there is at least one bug when you disconnect an audio bluetooth headset
// since we only get notification of route having changed, we cannot tell if that is due to:
// -bluetooth headset disconnected or
// -user wanted to use earpiece
// the only thing we can assume is that when we lost a device, it must be a bluetooth one (strong hypothesis though)
if ([[notif.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue] ==
AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
bluetoothAvailable = NO;
}
bool speakerEnabled = false;
CFStringRef lNewRoute = CFSTR("Unknown");
UInt32 lNewRouteSize = sizeof(lNewRoute);
OSStatus lStatus = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &lNewRouteSize, &lNewRoute);
if (!lStatus && lNewRouteSize > 0) {
NSString *route = (__bridge NSString *)lNewRoute;
CFStringRef newRoute = CFSTR("Unknown");
UInt32 newRouteSize = sizeof(newRoute);
OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &newRouteSize, &newRoute);
if (!status && newRouteSize > 0) {
NSString *route = (__bridge NSString *)newRoute;
LOGI(@"Current audio route is [%s]", [route UTF8String]);
speakerEnabled = [route isEqualToString:@"Speaker"] || [route isEqualToString:@"SpeakerAndMicrophone"];
if (!IPAD && [route isEqualToString:@"HeadsetBT"] && !speakerEnabled) {
lm.bluetoothEnabled = TRUE;
lm.bluetoothAvailable = TRUE;
NSDictionary *dict = [NSDictionary
dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:lm.bluetoothAvailable], @"available", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneBluetoothAvailabilityUpdate
object:lm
userInfo:dict];
bluetoothAvailable = TRUE;
bluetoothEnabled = TRUE;
} else {
lm.bluetoothEnabled = FALSE;
bluetoothEnabled = FALSE;
}
CFRelease(lNewRoute);
}
if (speakerEnabled != lm.speakerEnabled) { // Reforce value
lm.speakerEnabled = lm.speakerEnabled;
NSDictionary *dict =
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:bluetoothAvailable], @"available", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneBluetoothAvailabilityUpdate
object:self
userInfo:dict];
CFRelease(newRoute);
}
}
- (void)setSpeakerEnabled:(BOOL)enable {
OSStatus ret;
speakerEnabled = enable;
UInt32 override = kAudioSessionUnspecifiedError;
if (enable && [self allowSpeaker]) {
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride),
&audioRouteOverride);
bluetoothEnabled = FALSE;
} else {
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride),
&audioRouteOverride);
if (!enable && bluetoothAvailable) {
UInt32 bluetoothInputOverride = bluetoothEnabled;
ret = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
sizeof(bluetoothInputOverride), &bluetoothInputOverride);
// if setting bluetooth failed, it must be because the device is not available
// anymore (disconnected), so deactivate bluetooth.
if (ret != kAudioSessionNoError) {
bluetoothAvailable = bluetoothEnabled = FALSE;
}
}
if (bluetoothAvailable) {
UInt32 bluetoothInputOverride = bluetoothEnabled;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
sizeof(bluetoothInputOverride), &bluetoothInputOverride);
if (override != kAudioSessionNoError) {
if (enable && [self allowSpeaker]) {
override = kAudioSessionOverrideAudioRoute_Speaker;
ret = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(override), &override);
bluetoothEnabled = FALSE;
} else {
override = kAudioSessionOverrideAudioRoute_None;
ret = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(override), &override);
}
}
if (ret != kAudioSessionNoError) {
LOGE(@"Failed to change audio route: err %d", ret);
}
}

View file

@ -41,7 +41,7 @@
<action selector="onHistoryClick:" destination="-1" eventType="touchUpInside" id="22"/>
</connections>
</button>
<button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="8" userLabel="contactsButton" customClass="UIIconButton">
<button opaque="NO" tag="3" contentMode="scaleToFill" selected="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="8" userLabel="contactsButton" customClass="UIIconButton">
<rect key="frame" x="90" y="0.0" width="90" height="66"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Contacts"/>

View file

@ -39,36 +39,13 @@ static void audioRouteChangeListenerCallback(void *inUserData, // 1
[button update];
}
- (void)initUISpeakerButton {
INIT_WITH_COMMON {
AudioSessionInitialize(NULL, NULL, NULL, NULL);
OSStatus lStatus = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback, (__bridge void *)(self));
if (lStatus) {
LOGE(@"cannot register route change handler [%ld]", lStatus);
}
}
- (id)init {
self = [super init];
if (self) {
[self initUISpeakerButton];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initUISpeakerButton];
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (self) {
[self initUISpeakerButton];
}
return self;
}

View file

@ -9,3 +9,6 @@
#import "Log.h"
#import "Utils.h"
#import "UISpeakerButton.h"
#import "UIBluetoothButton.h"

@ -1 +1 @@
Subproject commit 218db02a1ab4590d31032b4cbce25b5c34d508e7
Subproject commit 60708a53ab17ccb5084f3ffcbc288edbb5bd3633