mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
audio: rework bluetooth headset recognition
This commit is contained in:
parent
6ed2bd5726
commit
e06564105f
11 changed files with 572 additions and 450 deletions
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,3 +9,6 @@
|
|||
|
||||
#import "Log.h"
|
||||
#import "Utils.h"
|
||||
|
||||
#import "UISpeakerButton.h"
|
||||
#import "UIBluetoothButton.h"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 218db02a1ab4590d31032b4cbce25b5c34d508e7
|
||||
Subproject commit 60708a53ab17ccb5084f3ffcbc288edbb5bd3633
|
||||
Loading…
Add table
Reference in a new issue