Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tv.data;
     18 
     19 import android.support.annotation.NonNull;
     20 import android.text.TextUtils;
     21 import android.view.KeyEvent;
     22 import com.android.tv.common.util.StringUtils;
     23 import com.android.tv.data.api.Channel;
     24 import java.util.Objects;
     25 
     26 /** A convenience class to handle channel number. */
     27 public final class ChannelNumber implements Comparable<ChannelNumber> {
     28     private static final int[] CHANNEL_DELIMITER_KEYCODES = {
     29         KeyEvent.KEYCODE_MINUS,
     30         KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
     31         KeyEvent.KEYCODE_PERIOD,
     32         KeyEvent.KEYCODE_NUMPAD_DOT,
     33         KeyEvent.KEYCODE_SPACE
     34     };
     35 
     36     /** The major part of the channel number. */
     37     public String majorNumber;
     38     /** The flag which indicates whether it has a delimiter or not. */
     39     public boolean hasDelimiter;
     40     /** The major part of the channel number. */
     41     public String minorNumber;
     42 
     43     public ChannelNumber() {
     44         reset();
     45     }
     46 
     47     /**
     48      * {@code lhs} and {@code rhs} are equivalent if {@link ChannelNumber#compare(String, String)}
     49      * is 0 or if only one has a delimiter and both {@link ChannelNumber#majorNumber} equals.
     50      */
     51     public static boolean equivalent(String lhs, String rhs) {
     52         if (compare(lhs, rhs) == 0) {
     53             return true;
     54         }
     55         // Match if only one has delimiter
     56         ChannelNumber lhsNumber = parseChannelNumber(lhs);
     57         ChannelNumber rhsNumber = parseChannelNumber(rhs);
     58         return lhsNumber != null
     59                 && rhsNumber != null
     60                 && lhsNumber.hasDelimiter != rhsNumber.hasDelimiter
     61                 && lhsNumber.majorNumber.equals(rhsNumber.majorNumber);
     62     }
     63 
     64     public void reset() {
     65         setChannelNumber("", false, "");
     66     }
     67 
     68     private void setChannelNumber(String majorNumber, boolean hasDelimiter, String minorNumber) {
     69         this.majorNumber = majorNumber;
     70         this.hasDelimiter = hasDelimiter;
     71         this.minorNumber = minorNumber;
     72     }
     73 
     74     @Override
     75     public String toString() {
     76         if (hasDelimiter) {
     77             return majorNumber + Channel.CHANNEL_NUMBER_DELIMITER + minorNumber;
     78         }
     79         return majorNumber;
     80     }
     81 
     82     @Override
     83     public int compareTo(@NonNull ChannelNumber another) {
     84         int major = Integer.parseInt(majorNumber);
     85         int minor = hasDelimiter ? Integer.parseInt(minorNumber) : 0;
     86 
     87         int opponentMajor = Integer.parseInt(another.majorNumber);
     88         int opponentMinor = another.hasDelimiter ? Integer.parseInt(another.minorNumber) : 0;
     89         if (major == opponentMajor) {
     90             return minor - opponentMinor;
     91         }
     92         return major - opponentMajor;
     93     }
     94 
     95     @Override
     96     public boolean equals(Object obj) {
     97         if (obj instanceof ChannelNumber) {
     98             ChannelNumber channelNumber = (ChannelNumber) obj;
     99             return TextUtils.equals(majorNumber, channelNumber.majorNumber)
    100                     && TextUtils.equals(minorNumber, channelNumber.minorNumber)
    101                     && hasDelimiter == channelNumber.hasDelimiter;
    102         }
    103         return super.equals(obj);
    104     }
    105 
    106     @Override
    107     public int hashCode() {
    108         return Objects.hash(majorNumber, hasDelimiter, minorNumber);
    109     }
    110 
    111     public static boolean isChannelNumberDelimiterKey(int keyCode) {
    112         for (int delimiterKeyCode : CHANNEL_DELIMITER_KEYCODES) {
    113             if (delimiterKeyCode == keyCode) {
    114                 return true;
    115             }
    116         }
    117         return false;
    118     }
    119 
    120     /**
    121      * Returns the ChannelNumber instance.
    122      *
    123      * <p>Note that all the channel number argument should be normalized by {@link
    124      * ChannelImpl#normalizeDisplayNumber}. The channels retrieved from {@link ChannelDataManager}
    125      * are already normalized.
    126      */
    127     public static ChannelNumber parseChannelNumber(String number) {
    128         if (number == null) {
    129             return null;
    130         }
    131         ChannelNumber ret = new ChannelNumber();
    132         int indexOfDelimiter = number.indexOf(Channel.CHANNEL_NUMBER_DELIMITER);
    133         if (indexOfDelimiter == 0 || indexOfDelimiter == number.length() - 1) {
    134             return null;
    135         } else if (indexOfDelimiter < 0) {
    136             ret.majorNumber = number;
    137             if (!isInteger(ret.majorNumber)) {
    138                 return null;
    139             }
    140         } else {
    141             ret.hasDelimiter = true;
    142             ret.majorNumber = number.substring(0, indexOfDelimiter);
    143             ret.minorNumber = number.substring(indexOfDelimiter + 1);
    144             if (!isInteger(ret.majorNumber) || !isInteger(ret.minorNumber)) {
    145                 return null;
    146             }
    147         }
    148         return ret;
    149     }
    150 
    151     /**
    152      * Compares the channel numbers.
    153      *
    154      * <p>Note that all the channel number arguments should be normalized by {@link
    155      * ChannelImpl#normalizeDisplayNumber}. The channels retrieved from {@link ChannelDataManager}
    156      * are already normalized.
    157      */
    158     public static int compare(String lhs, String rhs) {
    159         ChannelNumber lhsNumber = parseChannelNumber(lhs);
    160         ChannelNumber rhsNumber = parseChannelNumber(rhs);
    161         // Null first
    162         if (lhsNumber == null && rhsNumber == null) {
    163             return StringUtils.compare(lhs, rhs);
    164         } else if (lhsNumber == null /* && rhsNumber != null */) {
    165             return -1;
    166         } else if (rhsNumber == null) {
    167             return 1;
    168         }
    169         return lhsNumber.compareTo(rhsNumber);
    170     }
    171 
    172     private static boolean isInteger(String string) {
    173         try {
    174             Integer.parseInt(string);
    175         } catch (NumberFormatException | NullPointerException e) {
    176             return false;
    177         }
    178         return true;
    179     }
    180 }
    181